音视频处理之FFmpeg+SDL+MFC视频播放器20180411
一、FFmpeg+SDL+MFC视频播放器
1.MFC知识
1).创建MFC工程的方法
打开VC++
文件->新建->项目->MFC应用程序
应用程序类型->基于对话框
取消勾选"使用unicode库"
其中,在创建的过程中,单个文档表示意思是只有一个页面(窗口),多个文档表示的意思是有多个页面(窗口)。
2).设置控件
找到“工具箱”,就可以将相应的控件拖拽至应用程序对话框中
常用控件有:Button,Edit Control,Static Text等
找到“属性”选项卡
可以在“Caption”属性上修改控件上的文字
可以在“ID”属性上修改控件上的ID(ID是控件的标识,不可重复)
3).添加消息响应函数
双击Button控件,就可以给该控件添加消息响应函数。
在菜单栏的 项目->类向导 处,可以添加更多种类的消息响应函数。
如果已经添加了响应函数的控件删除时,不能直接删出,如果直接删除就要手动去删除添加的相关响应的操作代码,所以正确删除这个 一般是先点击项目 类向导中该控件对应的删除处理程序,再来进行删除界面上的。
熟悉的话,也可以在相应的地方手动进行操作。
4).MFC最简单的弹出消息框的函数是AfxMessageBox("xxx");
5).MFC中新建一个XX项目,则会自动生成一个XX.CPP类,同时如果有
一个对话框则还会有对应一个类 xxDlg.cpp(也是MFC自动生成),运行的过程是,先启动xx.cpp的初始化实例函数,由xx.cpp加载xxDlg.cpp
6).对话框的弹出:首先创建这个对话框的类,然后调用其相关的Doxxx的方法。
CFileDialog dlg();//打开一个对话框
dlg.DoModel() //弹出模式对话框,不能操作别的,只能操作这个对话框中的,点击确认后才可以继续往下走
7).在类向导中的成员变量栏,定义指定ID的成员变量,就可以通过该变量来访问ID对应的控件,或者说是操作对应的控件。
8).SDLmain.lib只在控制台中用到
9).mfc中字符串的类为CString,同时printf在mfc中已经没有用了
10).MFC中事件触发的线程栈比较小,一般如果耗栈大的,必须开辟一个新的线程(AfsBeginThread(函数名,函数的输入参数),其中的线程函数格式固定)
2.FFmpeg + SDL + MFC实现图形界面视频播放器
1).FFmpeg解码器与MFC的整合
需要将视频文件路径从MFC界面上的 Edit Control 控件传递给FFmpeg解码器
GetWindowText()
2).SDL与MFC的整合
需要将SDL显示的画面绘制到MFC的 Picture Control 控件上。
SDL_CreateWindowFrom()
PS:SDL2有一个Bug。在系统退出的时候会把显示图像的控件隐藏起来,因此需要调用该控件的ShowWindow()方法将控件显示出来。
3).在播放器播放,就应该让SDL将画面渲染到播放器定义的组件上
原先SDL创建的窗口是在控制台上的,调用的是SDL_CreateWindow函数,现在是在MFC的控件上创建窗口则调用的是SDL_CreateWindowFrom()函数
4).SDL播放完会隐藏起来窗口,导致我们找不到窗口,解决方法:SDL退出后再次调用MFC的相关函数来显示窗口
5).播放器显示的地方可以是在frame类型的控件上,也可以是在BitMap上,这样停止的时候就可以显示这个BitMap控件了,也就是可以显示背景图片了。
6).如果要添加菜单栏,在资源视图中的添加资源,新建menu,然后进行填充就可以出来菜单
menu资源怎么放到mfc的界面对话框中,是通过在mfc界面对话框属性中的杂项menu栏填入资源menu的ID即可
二、ywfPlayer代码
FFmpeg + SDL + MFC实现的图形界面视频播放器,取了个名字称为ywfPlayer
主要是ywfPlayerDlg.cpp文件,代码如下(基本上每一行都有注释):
- /*****************************************************************************
- * Copyright (C) 2017-2020 Hanson Yu All rights reserved.
- ------------------------------------------------------------------------------
- * File Module : ywfPlayerDlg.cpp
- * Description : ywfPlayerDlg Demo
- * Created : 2017.09.21.
- * Author : Yu Weifeng
- * Function List :
- * Last Modified :
- * History :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- #include "stdafx.h"
- #include "ywfPlayer.h"
- #include "ywfPlayerDlg.h"
- #include "afxdialogex.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- /*****************************************************************************
- -Fuction : CDialogEx
- -Description : 用于应用程序“关于”菜单项的 CAboutDlg 对话框
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- class CAboutDlg : public CDialogEx
- {
- public:
- CAboutDlg();
- // 对话框数据
- #ifdef AFX_DESIGN_TIME
- enum { IDD = IDD_ABOUTBOX };
- #endif
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
- // 实现
- protected:
- DECLARE_MESSAGE_MAP()
- };
- /*****************************************************************************
- -Fuction : CDialogEx
- -Description : 用于应用程序“关于”菜单项的 CAboutDlg 对话框
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
- {
- }
- /*****************************************************************************
- -Fuction : DoDataExchange
- -Description : DoDataExchange
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CAboutDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
- END_MESSAGE_MAP()
- // CywfPlayerDlg 对话框
- /*****************************************************************************
- -Fuction : CywfPlayerDlg
- -Description : CywfPlayerDlg
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- CywfPlayerDlg::CywfPlayerDlg(CWnd* pParent /*=NULL*/)
- : CDialog(IDD_YWFPLAYER_DIALOG, pParent)
- {
- m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
- }
- /*****************************************************************************
- -Fuction : DoDataExchange
- -Description : DoDataExchange
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialog::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CywfPlayerDlg, CDialog)
- ON_WM_SYSCOMMAND()
- ON_WM_PAINT()
- ON_WM_QUERYDRAGICON()
- // ON_BN_CLICKED(IDOK, &CywfPlayerDlg::OnBnClickedOk)
- ON_BN_CLICKED(IDC_PLAY, &CywfPlayerDlg::OnBnClickedPlay)
- ON_BN_CLICKED(IDPAUSE, &CywfPlayerDlg::OnBnClickedPause)
- ON_BN_CLICKED(IDSTOP, &CywfPlayerDlg::OnBnClickedStop)
- ON_COMMAND(ID_OPENFILE, &CywfPlayerDlg::Openfile)
- //ON_COMMAND(IDABORT, &CywfPlayerDlg::OnIdAbort)
- ON_COMMAND(IDEXIT, &CywfPlayerDlg::OnIdExit)
- ON_COMMAND(ID_ABOUT, &CywfPlayerDlg::OnAbout)
- END_MESSAGE_MAP()
- /*****************************************************************************
- -Fuction : OnInitDialog
- -Description : // CywfPlayerDlg 消息处理程序
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- BOOL CywfPlayerDlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
- // 将“关于...”菜单项添加到系统菜单中。
- // IDM_ABOUTBOX 必须在系统命令范围内。
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- BOOL bNameValid;
- CString strAboutMenu;
- bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
- ASSERT(bNameValid);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
- // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
- // 执行此操作
- SetIcon(m_hIcon, TRUE); // 设置大图标
- SetIcon(m_hIcon, FALSE); // 设置小图标
- // TODO: 在此添加额外的初始化代码
- return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
- }
- /*****************************************************************************
- -Fuction : OnSysCommand
- -Description : OnSysCommand
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- }
- else
- {
- CDialog::OnSysCommand(nID, lParam);
- }
- }
- /*****************************************************************************
- -Fuction : OnPaint
- -Description :
- // 如果向对话框添加最小化按钮,则需要下面的代码
- // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
- // 这将由框架自动完成。
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // 用于绘制的设备上下文
- SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), );
- // 使图标在工作区矩形中居中
- int cxIcon = GetSystemMetrics(SM_CXICON);
- int cyIcon = GetSystemMetrics(SM_CYICON);
- CRect rect;
- GetClientRect(&rect);
- int x = (rect.Width() - cxIcon + ) / ;
- int y = (rect.Height() - cyIcon + ) / ;
- // 绘制图标
- dc.DrawIcon(x, y, m_hIcon);
- }
- else
- {
- CDialog::OnPaint();
- }
- }
- /*****************************************************************************
- -Fuction : OnQueryDragIcon
- -Description :
- //当用户拖动最小化窗口时系统调用此函数取得光标
- //显示
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- HCURSOR CywfPlayerDlg::OnQueryDragIcon()
- {
- return static_cast<HCURSOR>(m_hIcon);
- }
- /*****************************************************************************
- -Fuction : OnBnClickedOk
- -Description :
- // TODO: 在此添加控件通知处理程序代码
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::OnBnClickedPlay()
- {
- // CString strSet("123");
- // AfxMessageBox(strSet);
- // CDialog::OnOK();
- m_iThreadPauseFlag = ;
- }
- /*****************************************************************************
- -Fuction : OnBnClickedPause
- -Description :
- // TODO: 在此添加控件通知处理程序代码
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::OnBnClickedPause()
- {
- m_iThreadPauseFlag = ;
- }
- /*****************************************************************************
- -Fuction : OnBnClickedStop
- -Description :
- // TODO: 在此添加控件通知处理程序代码
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::OnBnClickedStop()
- {
- m_iThreadExitFlag = ;
- }
- /*****************************************************************************
- -Fuction : Openfile
- -Description :
- // TODO: 在此添加控件通知处理程序代码
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::Openfile()
- {
- CFileDialog dlg(TRUE, NULL, NULL, NULL, NULL);///TRUE为OPEN对话框,FALSE为SAVE AS对话框
- if (dlg.DoModal() == IDOK)
- {
- m_strURL = dlg.GetPathName();
- pThreadYwfPlayer = AfxBeginThread((AFX_THREADPROC)YwfPlayerThread, (LPVOID)this);//开启线程
- }
- }
- /*****************************************************************************
- -Fuction : OnIdExit
- -Description :
- // TODO: 在此添加控件通知处理程序代码
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::OnIdExit()
- {
- OnCancel();//mfc函数
- }
- /*****************************************************************************
- -Fuction : OnAbout
- -Description :
- // TODO: 在此添加控件通知处理程序代码
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- void CywfPlayerDlg::OnAbout()
- {
- CAboutDlg dlg;
- dlg.DoModal();
- }
- /*****************************************************************************
- -Fuction : RefreshPlayThread
- -Description : 必须定义成静态的(c函数)才能作为线程函数
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- int CywfPlayerDlg::RefreshPlayThread(void *args)
- {
- if (NULL != args)
- {
- CywfPlayerDlg *pThis = (CywfPlayerDlg *)args;
- return pThis->RefreshPlayProc(NULL);//静态成员引用非静态成员必须要这样
- }
- }
- /*****************************************************************************
- -Fuction : RefreshPlayThread
- -Description : RefreshPlayThread
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- int CywfPlayerDlg::RefreshPlayProc(void *opaque)
- {
- m_iThreadExitFlag = ;
- m_iThreadPauseFlag = ;
- SDL_Event tEvent = { };
- //AfxMessageBox(m_strURL);
- while (!m_iThreadExitFlag)
- {
- if ( == m_iThreadPauseFlag)
- {
- tEvent.type = PLAY_REFRESH_EVENT;
- SDL_PushEvent(&tEvent);//发送事件给其他线程
- }
- SDL_Delay();//延时函数 填40的时候,视频会有种卡的感觉
- }
- //Break
- m_iThreadExitFlag = ;
- m_iThreadPauseFlag = ;
- tEvent.type = PLAY_BREAK_EVENT;
- SDL_PushEvent(&tEvent);//发送事件给其他线程 发送一个事件
- return ;
- }
- /*****************************************************************************
- -Fuction : RefreshPlayThread
- -Description : 必须定义成静态的(c函数)才能作为线程函数
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- UINT CywfPlayerDlg::YwfPlayerThread(LPVOID args)
- {
- if (NULL != args)
- {
- CywfPlayerDlg *pThis = (CywfPlayerDlg *)args;
- return pThis->YwfPlayerProc(args);//静态成员引用非静态成员必须要这样
- }
- }
- /*****************************************************************************
- -Fuction : main
- -Description : main
- -Input :
- -Output :
- -Return :
- * Modify Date Version Author Modification
- * -----------------------------------------------
- * 2017/09/21 V1.0.0 Yu Weifeng Created
- ******************************************************************************/
- int CywfPlayerDlg::YwfPlayerProc(LPVOID args)
- {
- CywfPlayerDlg *dlg = (CywfPlayerDlg *)args;
- /*------------FFmpeg----------------*/
- AVFormatContext *ptFormatContext = NULL;//封装格式上下文,内部包含所有的视频信息
- int i = ;
- int iVideoindex = ;//纯视频信息在音视频流中的位置,也就是指向音视频流数组中的视频元素
- AVCodecContext *ptCodecContext;//编码器相关信息上下文,内部包含编码器相关的信息,指向AVFormatContext中的streams成员中的codec成员
- AVCodec *ptCodec;//编码器,使用函数avcodec_find_decoder或者,该函数需要的id参数,来自于ptCodecContext中的codec_id成员
- AVFrame *ptFrame = NULL;//存储一帧解码后像素(采样)数据
- AVFrame *ptFrameAfterScale = NULL;//存储(解码数据)转换后的像素(采样)数据
- unsigned char *pucFrameAfterScaleBuf = NULL;//用于存储ptFrameAfterScale中的像素(采样)缓冲数据
- AVPacket *ptPacket = NULL;//存储一帧压缩编码数据
- int iRet = ;
- int iGotPicture = ;//解码函数的返回参数,got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero
- /*------------SDL----------------*/
- int iScreenWidth = , iScreenHeight = ;//视频的宽和高,指向ptCodecContext中的宽和高
- SDL_Window *ptSdlWindow = NULL;//用于sdl显示视频的窗口(用于显示的屏幕)
- SDL_Renderer* ptSdlRenderer = NULL;//sdl渲染器,把纹理数据画(渲染)到window上
- SDL_Texture* ptSdlTexture = NULL;//sdl纹理数据,用于存放像素(采样)数据,然后给渲染器
- SDL_Rect tSdlRect = { };//正方形矩形结构,存了矩形的坐标,长宽,以便确定纹理数据画在哪个位置,确定位置用,比如画在左上角就用这个来确定。被渲染器调用
- SDL_Thread *ptVideoControlTID = NULL;//sdl线程id,线程的句柄
- SDL_Event tSdlEvent = { };//sdl事件,代表一个事件
- /*------------像素数据处理----------------*/
- struct SwsContext *ptImgConvertInfo;//图像转换(上下文)信息,图像转换函数sws_scale需要的参数,由sws_getContext函数赋值
- /*------------FFmpeg----------------*/
- av_register_all();//注册FFmpeg所有组件
- avformat_network_init();//初始化网络组件
- //TRACE1("avcodec_configuration %s\r\n", avcodec_configuration());
- ptFormatContext = avformat_alloc_context();//分配空间给ptFormatContext
- //snprintf(strFilePath,sizeof(strFilePath),"%s", m_strURL);//不能使用如此字符,包括strncpy,memcpy都不行,因为在unicode下不行,同时拷贝传入的长度值从GetLength()来获取有问题
- int iLength = m_strURL.GetLength();
- int iBytes = WideCharToMultiByte(CP_ACP, , m_strURL, iLength, NULL, , NULL, NULL);
- char* strFilePath = new char[iBytes + ];
- memset(strFilePath, , iLength + );
- WideCharToMultiByte(CP_OEMCP, , m_strURL, iLength, strFilePath, iBytes, NULL, NULL);
- strFilePath[iBytes] = ;
- iRet = avformat_open_input(&ptFormatContext, strFilePath, NULL, NULL);
- if (iRet != )
- {//打开输入视频文件
- TRACE1 ("Couldn't open input stream:%s,%d\n", strFilePath, iRet);
- return -;
- }
- if (avformat_find_stream_info(ptFormatContext, NULL)<)
- {//获取视频文件信息
- OutputDebugString (L"Couldn't find stream information.\n");
- return -;
- }
- //获取编码器相关信息上下文,并赋值给ptCodecContext
- iVideoindex = -;
- for (i = ; i<ptFormatContext->nb_streams; i++)
- {
- if (ptFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- iVideoindex = i;
- break;
- }
- }
- if (iVideoindex == -)
- {
- OutputDebugString (L"Didn't find a video stream.\n");
- return -;
- }
- ptCodecContext = ptFormatContext->streams[iVideoindex]->codec;
- ptCodec = avcodec_find_decoder(ptCodecContext->codec_id);//查找解码器
- if (ptCodec == NULL)
- {
- OutputDebugString (L"Codec not found.\n");
- return -;
- }
- if (avcodec_open2(ptCodecContext, ptCodec, NULL)<)
- {//打开解码器
- OutputDebugString (L"Could not open codec.\n");
- return -;
- }
- ptPacket = (AVPacket *)av_malloc(sizeof(AVPacket));//分配保存解码前数据的空间
- ptFrame = av_frame_alloc();//分配结构体空间,结构体内部的指针指向的数据暂未分配,用于保存图像转换前的像素数据
- /*------------像素数据处理----------------*/
- ptFrameAfterScale = av_frame_alloc();//分配结构体空间,结构体内部的指针指向的数据暂未分配,用于保存图像转换后的像素数据
- pucFrameAfterScaleBuf = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, ptCodecContext->width, ptCodecContext->height));//分配保存数据的空间
- /*int avpicture_fill(AVPicture *picture, uint8_t *ptr,int pix_fmt, int width, int height);
- 这个函数的使用本质上是为已经分配的空间的结构体(AVPicture *)ptFrame挂上一段用于保存数据的空间,
- 这个结构体中有一个指针数组data[AV_NUM_DATA_POINTERS],挂在这个数组里。一般我们这么使用:
- 1) pFrameRGB=avcodec_alloc_frame();
- 2) numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);
- buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
- 3) avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,pCodecCtx->width, pCodecCtx->height);
- 以上就是为pFrameRGB挂上buffer。这个buffer是用于存缓冲数据的。
- ptFrame为什么不用fill空间。主要是下面这句:
- avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,packet.data, packet.size);
- 很可能是ptFrame已经挂上了packet.data,所以就不用fill了。*/
- avpicture_fill((AVPicture *)ptFrameAfterScale, pucFrameAfterScaleBuf, PIX_FMT_YUV420P, ptCodecContext->width, ptCodecContext->height);
- //sws开头的函数用于处理像素(采样)数据
- ptImgConvertInfo = sws_getContext(ptCodecContext->width, ptCodecContext->height, ptCodecContext->pix_fmt,
- ptCodecContext->width, ptCodecContext->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);//获取图像转换(上下文)信息
- /*------------SDL----------------*/
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER))
- {//初始化SDL系统
- TRACE1("Could not initialize SDL - %s\n", SDL_GetError());
- return -;
- }
- //SDL 2.0 Support for multiple windows
- iScreenWidth = ptCodecContext->width;
- iScreenHeight = ptCodecContext->height;
- //创建窗口SDL_Window
- //ptSdlWindow = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,iScreenWidth, iScreenHeight, SDL_WINDOW_OPENGL);
- //显示在MFC控件上
- ptSdlWindow = SDL_CreateWindowFrom(dlg->GetDlgItem(IDC_SCREEN)->GetSafeHwnd());
- if (!ptSdlWindow)
- {
- TRACE1("SDL: could not create window - exiting:%s\n", SDL_GetError());
- return -;
- }
- ptSdlRenderer = SDL_CreateRenderer(ptSdlWindow, -, );//创建渲染器SDL_Renderer
- //IYUV: Y + U + V (3 planes)
- //YV12: Y + V + U (3 planes)
- //创建纹理SDL_Texture
- ptSdlTexture = SDL_CreateTexture(ptSdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, ptCodecContext->width, ptCodecContext->height);
- tSdlRect.x = ;//x y值是左上角为圆点开始的坐标值,调整x y值以及w h值,就可以实现在窗口的指定位置显示,没有画面的地方为黑框
- tSdlRect.y = ;//当x y等于0,w h等于窗口的宽高时即为全屏显示,此时调整宽高大小,只需调整窗口大小即可
- tSdlRect.w = iScreenWidth;
- tSdlRect.h = iScreenHeight;
- ptVideoControlTID = SDL_CreateThread(RefreshPlayThread, NULL, (LPVOID)this);//创建一个线程
- while ()
- {//Event Loop
- SDL_WaitEvent(&tSdlEvent);//Wait,等待其他线程过来的事件
- if (tSdlEvent.type == PLAY_REFRESH_EVENT) //自定义刷新图像(播放)事件
- {
- /*------------FFmpeg----------------*/
- if (av_read_frame(ptFormatContext, ptPacket) >= ) //从输入文件读取一帧压缩数据
- {
- if (ptPacket->stream_index == iVideoindex)
- {
- iRet = avcodec_decode_video2(ptCodecContext, ptFrame, &iGotPicture, ptPacket);//解码一帧压缩数据
- if (iRet < )
- {
- OutputDebugString (L"Decode Error.\n");
- return -;
- }
- if (iGotPicture)
- {
- //图像转换,sws_scale()函数需要用到的转换信息,即第一个参数,是由sws_getContext函数获得的
- sws_scale(ptImgConvertInfo, (const uint8_t* const*)ptFrame->data, ptFrame->linesize, , ptCodecContext->height, ptFrameAfterScale->data, ptFrameAfterScale->linesize);
- /*------------SDL----------------*/
- SDL_UpdateTexture(ptSdlTexture, NULL, ptFrameAfterScale->data[], ptFrameAfterScale->linesize[]);//设置(更新)纹理的数据
- SDL_RenderClear(ptSdlRenderer);//先清除渲染器里的数据
- //SDL_RenderCopy( ptSdlRenderer, ptSdlTexture, &tSdlRect, &tSdlRect ); //将纹理的数据拷贝给渲染器
- SDL_RenderCopy(ptSdlRenderer, ptSdlTexture, NULL, NULL);//将纹理的数据拷贝给渲染器
- SDL_RenderPresent(ptSdlRenderer);//显示
- }
- }
- av_free_packet(ptPacket);//释放空间
- }
- else
- {
- m_iThreadExitFlag = ;//Exit Thread
- }
- }
- else if (tSdlEvent.type == SDL_QUIT) //也是SDL自带的事件,当点击窗口的×时触发//SDL_WINDOWENVENT sdl系统自带的事件,当拉伸窗口的时候会触发
- {
- m_iThreadExitFlag = ;
- }
- else if (tSdlEvent.type == PLAY_BREAK_EVENT) //自定义退出播放事件
- {
- break;
- }
- }
- /*------------像素数据处理----------------*/
- sws_freeContext(ptImgConvertInfo);//释放空间
- /*------------SDL----------------*/
- SDL_Quit();//退出SDL系统
- //SDL Hide Window When it finished
- dlg->GetDlgItem(IDC_SCREEN)->ShowWindow(SW_SHOWNORMAL);
- /*------------FFmpeg----------------*/
- av_frame_free(&ptFrameAfterScale);//释放空间
- av_frame_free(&ptFrame);//释放空间
- avcodec_close(ptCodecContext);//关闭解码器
- avformat_close_input(&ptFormatContext);//关闭输入视频文件
- return ;
- }
ywfPlayerDlg.cpp
具体代码见github:
https://github.com/fengweiyu/ywfPlayer
音视频处理之FFmpeg+SDL+MFC视频播放器20180411的更多相关文章
- 基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结
最近因为项目接近收尾阶段,所以变的没有之前那么忙了,所以最近重新拿起了之前的一些FFMPEG和SDL的相关流媒体播放器的例子在看. 同时自己也用FFMPEG2.01,SDL2.01结合MFC以及网上罗 ...
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] ...
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 用JavaCV改写“100行代码实现最简单的基于FFMPEG+SDL的视频播放器 ”
FFMPEG的文档少,JavaCV的文档就更少了.从网上找到这篇100行代码实现最简单的基于FFMPEG+SDL的视频播放器.地址是http://blog.csdn.net/leixiaohua102 ...
- 音视频处理之FFmpeg+SDL视频播放器20180409
一.FFmpeg视频解码器 1.视频解码知识 1).纯净的视频解码流程 压缩编码数据->像素数据. 例如解码H.264,就是“H.264码流->YUV”. 2).一般的视频解码流程 视频码 ...
- FFMPEG+SDL实现视频播放器
一. 前言 基于学习ffmpeg和sdl,写一个视频播放器是个不错的练手项目. 视频播放器的原理很多人的博客都有讲过,这里出于自己总结的目的,还是会做一些概况. 二. 视频播放器基本原理 2.1 解封 ...
- 【转】100行代码实现最简单的基于FFMPEG+SDL的视频播放器
FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手.我刚接触FFMPEG的时候也感觉不知从何学起. 因此我把自己做项目过程中实现的一个非常简单的视频播放器 ...
随机推荐
- 机器学习(一):记一次k一近邻算法的学习与Kaggle实战
本篇博客是基于以Kaggle中手写数字识别实战为目标,以KNN算法学习为驱动导向来进行讲解. 写这篇博客的原因 什么是KNN kaggle实战 优缺点及其优化方法 总结 参考文献 写这篇博客的原因 写 ...
- Python更新库
查看系统里过期的python库,可以用pip命令 [root@vnode33 sim-enb-sgi]# pip list #列出所有安装的库 Package Version ------------ ...
- “Hello World!”团队第六周的第三次会议
今天是我们团队“Hello World!”团队第六周召开的第三次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.代码 一 ...
- linux下创建virtualenv时指定python版本
virtualenv是python开发中一个重要的工具,它可以帮助我们创建一个干净的python解释环境,创建虚拟环境时,这个虚拟环境的python版本往往是系统默认的2.x版本.别急,我们只需要一条 ...
- OcLint的使用
一.介绍 OCLint是一个强大的静态代码分析工具,可以用来提高代码质量,查找潜在的bug,主要针对c,c++和Objective-c的静态分析.功能非常强大,而且是出自国人之手.项目地址:http: ...
- Scala入门系列(三):数组
Array 与Java的Array类似,也是长度不可变的数组,此外,由于Scala与Java都是运行在JVM中,双方可以互相调用,因此Scala数组的底层实际上是Java数组. 注意:访问数组中元素使 ...
- 转 彻底理解js中的&&和||
javascript中,&&和||的用法比较神奇,经常用在对象上,例如a || b,如果a不存在,则返回b.a && b,如果a存在,则返回b,否则返回a. 光这样看, ...
- 9th 学习博客:使用Codebloks实现C++的图形化界面
使用开发工具codeblocks,添加ResEdit.exe这个控件,可以很方便地进行图形化编辑,这是在网上找得教程,实现的是最基本的在对话框内添加按钮,并实现单击响应在控制台输出相应的文字. mai ...
- EasyUseCase 一款脑图转化 Excel 测试用例工具 (1.2 版本升级)
EasyUseCase 本工具由本人自主开发.经过内部实践有效提升测试用例编写效率200% 覆盖率可度量.利用读取xmind软件图表转换符合国人基本需求的测试用例,让手动写Excel用例的日子过去,发 ...
- Hibernate Validation,Spring mvc 数据验证框架注解
1.@NotNull:不能为 Null,但是可以为Empty:用在基本数据类型上. @NotNull(message="{state.notnull.valid}", groups ...