作者:手机用户2602927383 | 来源:互联网 | 2023-07-10 19:26
简介
本教程采用的ffmpeg是3.2版本,SDL是2.0版本,Qt控制台程序,编译器是mingwin64,在window下创建的工程,没有测试linux是否可用,用户可自行测试。另外本教程是在雷神的基础上“翻新”的,雷神采用的是旧版本的ffmpeg,由于新版本的ffmpeg修改了很多流程和API所以本人,根据新版本的API函数修改了代码,供大家交流使用。(在此感谢雷神!)
前言
1、在配置Qt、ffmpeg、sdl过程中编译的时候出现未定义的winmain函数,这个问题是由于SDL的头文件引起的,需要在main.cpp文件的前面加上#undef main,如下图所示。
流程图
1、ffmpeg解码流程图
2、SDL流程图(与原来一致)
其中SDL_Window个人理解就是一个画板,可以在上面创建多个Rect区域,这些区域都是用来显示视频画面的;SDL_Texture是一个纹理特征对象,即是一帧画面,用于渲染在Rect区域;而SDL_Renderer就是一个渲染器,负责渲染画面。(参考雷神的关系图,一目了然)
做监控视频时候的多窗口显示,可以这样设计,利用Rect
播放器代码
#include
#ifdef __cplusplus#define __STDC_CONSTANT_MACROS#ifdef _STDINT_H#undef _STDINT_H#endif# include
#endif
extern "C"
{#include"libavcodec/avcodec.h"#include"libavformat/avformat.h"#include"libswscale/swscale.h"#include "libavutil/imgutils.h"#include"SDL.h"
}
#undef main
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);AVFormatContext *pFormatCtx;int i,videoindex;AVCodecContext *pCodecCtx;AVCodec * pCodec;AVFrame * pFrame,*pFrameYUV;uint8_t *out_buffer;AVPacket * packet;struct SwsContext *img_convert_ctx;int screen_w,screen_h;SDL_Window *screen;SDL_Renderer*sdlRenderer;SDL_Texture *sdlTexture;SDL_Rect sdlRect;FILE* fp_yuv;int ret,got_picture;char filepath[]&#61;"d://boat.MP4";av_register_all();avformat_network_init();pFormatCtx&#61;avformat_alloc_context();if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!&#61;0){printf("无法打开信息流");return -1;}if(avformat_find_stream_info(pFormatCtx,NULL)<0){printf("无法查找到流信息");return -1;}videoindex&#61;-1;for(i&#61;0;inb_streams;i&#43;&#43;){if(pFormatCtx->streams[i]->codecpar->codec_type&#61;&#61;AVMEDIA_TYPE_VIDEO){videoindex&#61;i;break;}}if(videoindex<0){printf("没有视频流");return -1;}pCodecCtx&#61;avcodec_alloc_context3(NULL);if(!pCodecCtx){printf("分配解码器上下文内存失败");return -1;}//获取编解码器if(avcodec_parameters_to_context(pCodecCtx,pFormatCtx->streams[videoindex]->codecpar)<0){printf("拷贝视频流解码器参数到解码器对象失败");return -1;}pCodec&#61;avcodec_find_decoder(pCodecCtx->codec_id);if(!pCodec){printf("查找解码器失败");return -1;}//打开解码器if(avcodec_open2(pCodecCtx,pCodec,NULL)<0){printf("打开解码器失败");return -1;}printf("------------------------------视频信息-----------------------\n");av_dump_format(pFormatCtx,0,filepath,0);printf("------------------------------视频信息-----------------------\n");pFrame&#61;av_frame_alloc();pFrameYUV&#61;av_frame_alloc();out_buffer&#61;(uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,1));av_image_fill_arrays(pFrameYUV->data,pFrameYUV->linesize,out_buffer,AV_PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,1);packet&#61;(AVPacket*)av_malloc(sizeof (AVPacket));img_convert_ctx&#61;sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);if(SDL_Init(SDL_INIT_VIDEO| SDL_INIT_AUDIO|SDL_INIT_TIMER)){printf("无法初始化SDL");return -1;}screen_w&#61;pCodecCtx->width;screen_h&#61;pCodecCtx->height;screen&#61;SDL_CreateWindow("播放器",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,screen_w,screen_h,SDL_WINDOW_OPENGL);if(!screen){printf("创建播放窗口失败");return -1;}sdlRenderer&#61;SDL_CreateRenderer(screen,-1,0);sdlTexture&#61;SDL_CreateTexture(sdlRenderer,SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING,screen_w,screen_h);sdlRect.x&#61;0;sdlRect.y&#61;0;sdlRect.w&#61;screen_w;sdlRect.h&#61;screen_h;while (av_read_frame(pFormatCtx,packet)>&#61;0) {if(packet->stream_index&#61;&#61;videoindex){ret&#61;avcodec_send_packet(pCodecCtx,packet);if(ret<0){printf("发送失败");}while (ret>&#61;0) {ret&#61;avcodec_receive_frame(pCodecCtx,pFrame);if(ret&#61;&#61;AVERROR(EAGAIN)||ret&#61;&#61;AVERROR_EOF){break;}else if(ret<0){//释放资源
// av_frame_unref(pFrame);
// av_frame_unref(pFrameYUV);}if(ret>&#61;0){sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameYUV->data,pFrameYUV->linesize);
#if 0SDL_UpdateTexture(sdlTexture,NULL,pFrameYUV->data[0],pFrameYUV->linesize[0]);
#elseSDL_UpdateYUVTexture(sdlTexture,&sdlRect,pFrameYUV->data[0],pFrameYUV->linesize[0],pFrameYUV->data[1],pFrameYUV->linesize[1],pFrameYUV->data[2],pFrameYUV->linesize[2]);
#endifSDL_RenderClear(sdlRenderer);SDL_RenderCopy(sdlRenderer,sdlTexture,NULL,&sdlRect);SDL_RenderPresent(sdlRenderer);SDL_Delay(40);}}}av_packet_unref(packet);}SDL_Quit();av_frame_unref(pFrame);av_frame_unref(pFrameYUV);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);return a.exec();
}