当前位置: 首页 > Linux

C++FFmpeg4.1版东京热初体验

时间:2023-04-06 11:44:42 Linux

我的目的是通过FFmpeg解码播放h264文件;开始表演操作;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;第一步,打开http://ffmpeg.org/,找到Download,找到WindowsBuilds,点击进入需要下载两个版本(如果你写的程序是32位的程序,就下载32位的,如果你的程序是64位的,需要下载64位的)1、Shared(dll文件)2、Dev(包括头文件、lib、示例代码)下载后等待使用;第二步,新建一个MFC程序,然后运行(生成一个debug文件夹);将刚才下载的FFmpeg-dev中的lib和include文件夹复制到工程路径下(我放在cpp文件的上层目录,这个看你自己对工程架构设计的理解)里面有8个dll文件目录的debug文件夹,注意目录;这个目录其实就是exe所在的目录;第三步,配置FFmpeg1,配置include右键项目属性,configureproperties->C/C++->General->AdditionalIncludeDirectory->Type..include(因为刚才复制include目录的时候,我把它在cpp文件的上层,所以是.include)2.配置lib右键项目属性,配置属性->Linker->General->Additionallibrarydirectory->..lib(因为我刚才复制的时候lib目录,我放在cpp文件的上层,所以是.lib)3.配置lib文件右键项目属性,ConfigurationProperties->Linker->Input->AdditionalDependencies->输入FFmpeglib目录下的所有lib文件名打开cpp文件包含FFmpeg头文件includeinclude}注1:#define__STDC_CONSTANT_MACROS这个需要在include前面定义注2:因为第三步第三项已经输入了所有的lib,所以不需要通过#pragmacomment(lib,"xxx.lib")链接再编译并运行测试。编译时如有错误,自行百度解决;如果没有错误就最好了,祝你成功。第四步,拖动界面。因为之前看过雷神的教程,界面是按这个拖出来的;文件按钮是选择文件的按钮。选择文件后,在EditControl控件中显示路径。你可以自己做。;第五步,根据上面的接口实现代码实现逻辑;大体逻辑:选择文件路径->点击播放->解码文件->显示在Picture控件中;我们重点关注视频解码点击播放的响应事件//点击播放按钮响应时间voidCMFCFFmpeg41Player1Dlg::OnBnClickedButton2(){//TODO:在这里添加控件通知处理代码if(mVideoPath.IsEmpty()){MessageBox(TEXT("请选择视频文件路径"));return;}AfxBeginThread(Thread_Play,this);}mVideoPath是EditControl控件的Value关联对象;先判断是否为空,然后消息提示;如果不为空,则启动解码线程,并将this指针传递给线程函数;看Thread_Play注意:Thread_Play的定义要遵循特定的格式UINTThread_Play(LPVOIDlpParam){Play_H264_File(lpParam);cout<<"线程播放文件结束"<mVideoEdit,(LPSTR)文件路径,250);//mVideoEdit是文件路径对象EditControl控件关联Control关联对象pFormatCtx=avformat_alloc_context();//获取解码上下文//解码上下文关联文件if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){cout<<"打开视频文件失败"<nb_streams;i++){if(pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){v_index=i;break;}}//判断是否有是视频帧if(v_index<0){cout<<"目标不是视频文件"<streams[v_index]->avg_frame_rate.num/pFormatCtx->streams[v_index]->avg_frame_rate.den;//每秒多少帧dely_time=1000/fps;//获取解码上下文对象pCodecCtx=avcodec_alloc_context3(NULL);//根据解码上下文初始化解码上下文if(avcodec_parameters_to_context(pCodecCtx,pFormatCtx->streams[v_index]->codecpar)<0){cout<<"复制解码器数据失败"<codec_id);//打开解码器if(avcodec_open2(pCodecCtx,pCodec,NULL)!=0){cout<<"Decoderfailedtoopen"<width,pCodecCtx->height,1);//应用缓存对象out_buffer=(uint8_t*)av_malloc(v_size);//将自定义缓存空间绑定到输出AVFrameav_image_fill_arrays(pFrameYUV->data,pFrameYUV->linesize,out_buffer,AV_PIX_FMT_YUV420P,pCodecCtx->宽度,pCodecCtx->高度,1);while(av_read_frame(pFormatCtx,packet)>=0){//读取一帧数据if(packet->stream_index==v_index){//判断是否是视频帧if(avcodec_send_packet(pCodecCtx,packet)!=0){//发送解码数据cout<<"发送解码数据出错"<include然后添加到Play_H264_File函数中使用。我发布了完整的代码;voidPlay_H264_File(LPVOIDlpParam){////////////////////FFmpeg/////////////////////AVFormatContext*pFormatCtx;AVCodecContext*pCodecCtx;AVCodec*pCodec;AVFrame*pFrame;AVFrame*pFrameYUV;AVPacket*packet;uint8_t*out_buffer;intv_index;intv_size;CMFCFFmpeg41Player1Dlg*dlg;intdely_time;//////////////////////////SDL///////////////////////SDL_Window*mSDL_Window;SDL_Renderer*mSDL_Renderer;SDL_Texture*mSDL_Texture;structSwsContext*mSwsContext;intscreenW;intscreenH;SDL_RectmSDL_Rect;dlg=(CMFCFFmpeg41Player1Dlg*)lpParam;////////////////////////////////////SDL////////////////////////if(SDL_Init(SDL_INIT_VIDEO)){cout<<"SDL初始化失败"<<结束;返回;}//////////////////////FFmpeg//////////////////////////charfilepath[250]={0};GetWindowTextA(dlg->mVideoEdit,(LPSTR)filepath,250);pFormatCtx=avformat_alloc_context();if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){cout<<"视频文件打开失败"<nb_streams;i++){if(pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){v_index=i;break;}}if(v_index<0){cout<<"目标不是视频文件"<streams[v_index]->avg_frame_rate.num/pFormatCtx->streams[v_index]->avg_frame_rate.den;//每秒多少帧dely_time=1000/fps;cout<<"视频FPS="<streams[videoindex]->codec;if(avcodec_parameters_to_context(pCodecCtx,pFormatCtx->streams[v_index]->codecpar)<0){cout<<"copydecodingDecoderfailed"<codec_id);if(avcodec_open2(pCodecCtx,pCodec,NULL)!=0){cout<<"解码器打开失败"<width;mSDL_Rect.h=pCodecCtx->height;mSDL_Window=SDL_CreateWindowFrom(dlgV->GetDlgTem)->GetSafeHwnd());mSDL_Renderer=SDL_CreateRenderer(mSDL_Window,-1,0);mSDL_Texture=SDL_CreateTexture(mSDL_Renderer,SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING,pCodecCtx->宽度,pCodecCtx->高度);mSwsContext=sws_getContext(pCodecCtx->宽度,pCodecCtx->高度,pCodecCtx->pix_fmt,pCodecCtx->宽度,pCodecCtx->高度,AV_PIX_2FMTBLLPIC,SUV4YUVNULL,NULL);pFrame=av_frame_alloc();pFrameYUV=av_frame_alloc();packet=av_packet_alloc();v_size=av_image_get_buffer_size(AV_PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,1);out_buffer=(uint8_t*)av_malloc(v_size);av_image_fill_arrays(pFrameYUV->data,pFrameYUV->linesize,out_buffer,AV_PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,1);while(av_read_frame(pFormatCtx,packet)>=0){if(packet->stream_index==v_index){if(avcodec_send_packet(pCodecCtx,packet)!=0){cout<<"发送解码数据错误"<data,pFrame->linesize,0,pCodecCtx->height,pFrameYUV->data,pFrameYUV->linesize);SDL_UpdateTexture(mSDL_Texture,NULL,pFrameYUV->data[0],pFrameYUV->linesize[0]);SDL_RenderClear(mSDL_Renderer);SDL_RenderCopy(mSDL_Renderer,mSDL_Texture,NULL,NULL);SDL_RenderPresent(mSDL_Renderer);睡眠(延迟时间);}}av_free(out_buffer);av_frame_free(&pFrameYUV);av_frame_free(&pFrame);av_packet_free(&packet);sws_freeContext(mSwsContext);SDL_DestroyTexture(mSDL_Texture);SDL_DestroyRenderer(mSDL_Renderer);SDL_DestroyWindow(mSDL_Window);SDL_Quit();avcodec_free_context(&pCodecCtx);avformat_close_input(&pFormatCtx);avformat_free_context(pFormatCtx);功能已经实现;每个人都可以扩展它;pause函数是停止解码,加一个变量控制就好,stop是停止解码线程,也加一个变量控制;