热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

最简单的FFmpeg+SDL+Qt视频播放器

简介本教程采用的ffmpeg是3.2版本,SDL是2.0版本,Qt控制台程序,编译器是mingwin64,在window下创

简介

本教程采用的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();
}


推荐阅读
  • vue使用
    关键词: ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
author-avatar
手机用户2602927383
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有