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

FFmpeg+SDL播放器开发实现

FFmpeg和SDL的整合实现视频播放整合方式•FFmpeg解码器实现了:视频文件-YUV•SDL视频显示实现了:YUV-屏幕•FFmpegSDL
FFmpeg和SDL的整合实现视频播放

整合方式
• FFmpeg解码器实现了:视频文件->YUV
• SDL视频显示实现了:YUV->屏幕
• FFmpeg+SDL整合之后实现了:视频文件->YUV->屏幕

/*** 最简单的基于FFmpeg的视频播放器2(SDL升级版)* Simplest FFmpeg Player 2(SDL Update)** 雷霄骅 Lei Xiaohua* leixiaohua1020@126.com* 中国传媒大学/数字电视技术* Communication University of China / Digital TV Technology* http://blog.csdn.net/leixiaohua1020** 本程序实现了视频文件的解码和显示(支持HEVC,H.264,MPEG2等)。* 是最简单的FFmpeg视频解码方面的教程。* 通过学习本例子可以了解FFmpeg的解码流程。* 本版本中使用SDL消息机制刷新视频画面。* This software is a simplest video player based on FFmpeg.* Suitable for beginner of FFmpeg.**/#include #define __STDC_CONSTANT_MACROSextern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "SDL.h"
};//Refresh Event
#define SFM_REFRESH_EVENT (SDL_USEREVENT + 1)#define SFM_BREAK_EVENT (SDL_USEREVENT + 2)int thread_exit = 0;int sfp_refresh_thread(void* opaque) {thread_exit = 0;while (!thread_exit) {SDL_Event event;event.type = SFM_REFRESH_EVENT;SDL_PushEvent(&event);SDL_Delay(40);}thread_exit = 0;//BreakSDL_Event event;event.type = SFM_BREAK_EVENT;SDL_PushEvent(&event);return 0;
}int main(int argc, char* argv[])
{AVFormatContext* pFormatCtx;int i, videoindex;AVCodecContext* pCodecCtx;AVCodec* pCodec;AVFrame* pFrame, * pFrameYUV;uint8_t* out_buffer;AVPacket* packet;int ret, got_picture;//------------SDL----------------int screen_w, screen_h;SDL_Window* screen;SDL_Renderer* sdlRenderer;SDL_Texture* sdlTexture;SDL_Rect sdlRect;SDL_Thread* video_tid;SDL_Event event;struct SwsContext* img_convert_ctx;char filepath[] &#61; "屌丝男士.mov";//av_register_all();avformat_network_init();pFormatCtx &#61; avformat_alloc_context();if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) !&#61; 0) {printf("Couldn&#39;t open input stream.\n");return -1;}if (avformat_find_stream_info(pFormatCtx, NULL) <0) {printf("Couldn&#39;t find stream information.\n");return -1;}videoindex &#61; -1;for (i &#61; 0; i nb_streams; i&#43;&#43;)if (pFormatCtx->streams[i]->codecpar->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO) {videoindex &#61; i;break;}if (videoindex &#61;&#61; -1) {printf("Didn&#39;t find a video stream.\n");return -1;}AVCodecParameters* codecParameters &#61; pFormatCtx->streams[videoindex]->codecpar;pCodecCtx &#61; avcodec_alloc_context3(nullptr);avcodec_parameters_to_context(pCodecCtx, codecParameters);//pCodecCtx &#61; pFormatCtx->streams[videoindex]->codec;pCodec &#61; (AVCodec*)avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec &#61;&#61; NULL) {printf("Codec not found.\n");return -1;}if (avcodec_open2(pCodecCtx, pCodec, NULL) <0) {printf("Could not open codec.\n");return -1;}packet &#61; av_packet_alloc();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);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_TIMER)) {printf("Could not initialize SDL - %s\n", SDL_GetError());return -1;}//SDL 2.0 Support for multiple windowsscreen_w &#61; pCodecCtx->width;screen_h &#61; pCodecCtx->height;screen &#61; SDL_CreateWindow("Simplest ffmpeg player&#39;s Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,screen_w, screen_h, SDL_WINDOW_OPENGL);if (!screen) {printf("SDL: could not create window - exiting:%s\n", SDL_GetError());return -1;}sdlRenderer &#61; SDL_CreateRenderer(screen, -1, 0);//IYUV: Y &#43; U &#43; V (3 planes)//YV12: Y &#43; V &#43; U (3 planes)sdlTexture &#61; SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);sdlRect.x &#61; 0;sdlRect.y &#61; 0;sdlRect.w &#61; screen_w;sdlRect.h &#61; screen_h;packet &#61; (AVPacket*)av_malloc(sizeof(AVPacket));video_tid &#61; SDL_CreateThread(sfp_refresh_thread, NULL, NULL);//------------SDL End------------//Event Loopfor (;;) {//WaitSDL_WaitEvent(&event);if (event.type &#61;&#61; SFM_REFRESH_EVENT) {//------------------------------if (av_read_frame(pFormatCtx, packet) >&#61; 0) {if (packet->stream_index &#61;&#61; videoindex) {if (avcodec_send_packet(pCodecCtx, packet) <0) {printf("avcodec_send_packet failed!.\n");continue;}while (1) {ret &#61; avcodec_receive_frame(pCodecCtx, pFrame);if (ret !&#61; 0)break;sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);//SDL---------------------------SDL_UpdateTexture(sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0]);SDL_RenderClear(sdlRenderer);//SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect ); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);SDL_RenderPresent(sdlRenderer);//SDL End-----------------------}}av_packet_unref(packet);}else {//Exit Threadthread_exit &#61; 1;}}else if (event.type &#61;&#61; SDL_QUIT) {thread_exit &#61; 1;}else if (event.type &#61;&#61; SFM_BREAK_EVENT) {break;}}sws_freeContext(img_convert_ctx);SDL_Quit();//--------------av_frame_free(&pFrameYUV);av_frame_free(&pFrame);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);return 0;
}

进阶&#xff1a;脱离开发环境的独立播放器


因为VS会生成可执行文件&#xff08;在Debug文件夹中&#xff09;&#xff0c;利用argv参数进行视频文件的选择播放

main()函数的参数
• argc argv&#xff1a;全称为ARGument Counter 和 ARGument Vector。其中argv存储了来自于命令行的参数&#xff1b;而argc存储了参数的个数。
• 例如在命令行中输入“ffmpeg -i test.mkv test.ts ”&#xff0c;则argc取值为4&#xff0c; 而argv[]数组取值如下&#xff1a;
argv[0]&#61;“ffmpeg”
argv[1]&#61;“-i”
argv[2]&#61;“test.mkv”
argv[3]&#61;“test.ts”
• 动态链接库&#xff08;*.dll&#xff09;
动态链接库不能被编译进应用程序。因而使用应用程序的时候必须在相同目录下保存用到的动态链接库文件。
 

学习地址&#xff1a;https://ke.qq.com/course/5840494?flowToken&#61;1044368

你将获得详询课程

  • 掌握ffmpeg开发环境的快速搭建

  • 掌握音视频解复用流程以及解码流程

  • 掌握声音输出和画面渲染

  • 掌握音视频同步原理

训练营品质服务

  • 作业讲解 讲解课后作业&#xff0c;老师手把手指导教学

  • 专业老师答疑 学中有疑问&#xff0c;工作日24小时内可获得老师响应

  • 专属学习群 加入学员学习交流群&#xff0c;与相同目标的同学共同进步​​​​​​​



推荐阅读
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
author-avatar
勇淑丁
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有