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

实战ffmpeg与sdl实现最简单的视频播放器

流程:解复用-解码-yuv-交给纹理-交给渲染器-播放。其中前三步使用ffmpeg实现,后三步用sdl实现。#include

流程:
解复用->解码->yuv->交给纹理->交给渲染器->播放。
其中前三步使用ffmpeg实现,后三步用sdl实现。

#include
#include #include
#include
#include // compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endifint main(int argc, char *argv[]) {int ret &#61; -1;AVFormatContext *pFormatCtx &#61; NULL; //for opening multi-media fileint i, videoStream;AVCodecContext *pCodecCtxOrig &#61; NULL; //codec contextAVCodecContext *pCodecCtx &#61; NULL;struct SwsContext *sws_ctx &#61; NULL;AVCodec *pCodec &#61; NULL; // the codecerAVFrame *pFrame &#61; NULL;AVPacket packet;int frameFinished;float aspect_ratio;AVPicture *pict &#61; NULL;SDL_Rect rect;Uint32 pixformat; //for renderSDL_Window *win &#61; NULL;SDL_Renderer *renderer &#61; NULL;SDL_Texture *texture &#61; NULL;//set defualt size of window int w_width &#61; 640;int w_height &#61; 480;if(argc < 2) {//fprintf(stderr, "Usage: command \n");SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Usage: command ");return ret;}if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {//fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not initialize SDL - %s\n", SDL_GetError());return ret;}//Register all formats and codecsav_register_all();// Open video fileif(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!&#61;0){SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open video file!");goto __FAIL; // Couldn&#39;t open file}// Retrieve stream informationif(avformat_find_stream_info(pFormatCtx, NULL)<0){SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find stream infomation!");goto __FAIL; // Couldn&#39;t find stream information}// Dump information about file onto standard errorav_dump_format(pFormatCtx, 0, argv[1], 0);// Find the first video streamvideoStream&#61;-1;for(i&#61;0; i<pFormatCtx->nb_streams; i&#43;&#43;) {if(pFormatCtx->streams[i]->codec->codec_type&#61;&#61;AVMEDIA_TYPE_VIDEO) {videoStream&#61;i;break;}}if(videoStream&#61;&#61;-1){SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Din&#39;t find a video stream!");goto __FAIL;// Didn&#39;t find a video stream}// Get a pointer to the codec context for the video streampCodecCtxOrig&#61;pFormatCtx->streams[videoStream]->codec;// Find the decoder for the video streampCodec&#61;avcodec_find_decoder(pCodecCtxOrig->codec_id);if(pCodec&#61;&#61;NULL) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported codec!\n");goto __FAIL; // Codec not found}// Copy contextpCodecCtx &#61; avcodec_alloc_context3(pCodec);if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) !&#61; 0) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn&#39;t copy codec context");goto __FAIL;// Error copying codec context}// Open codecif(avcodec_open2(pCodecCtx, pCodec, NULL)<0) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open decoder!\n");goto __FAIL; // Could not open codec}// Allocate video framepFrame&#61;av_frame_alloc();w_width &#61; pCodecCtx->width;w_height &#61; pCodecCtx->height;win &#61; SDL_CreateWindow( "Media Player",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,w_width, w_height,SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if(!win){SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window by SDL"); goto __FAIL;}renderer &#61; SDL_CreateRenderer(win, -1, 0);if(!renderer){SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Renderer by SDL"); goto __FAIL;}pixformat &#61; SDL_PIXELFORMAT_IYUV;texture &#61; SDL_CreateTexture(renderer,pixformat, SDL_TEXTUREACCESS_STREAMING,w_width, w_height);// initialize SWS context for software scalingsws_ctx &#61; sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_YUV420P,SWS_BILINEAR,NULL,NULL,NULL);pict &#61; (AVPicture*)malloc(sizeof(AVPicture));avpicture_alloc(pict, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);// Read frames and save first five frames to diskwhile(av_read_frame(pFormatCtx, &packet)>&#61;0) {// Is this a packet from the video stream?if(packet.stream_index&#61;&#61;videoStream) {// Decode video frameavcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);// Did we get a video frame?if(frameFinished) {// Convert the image into YUV format that SDL usessws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,pFrame->linesize, 0, pCodecCtx->height,pict->data, pict->linesize);SDL_UpdateYUVTexture(texture, NULL, pict->data[0], pict->linesize[0],pict->data[1], pict->linesize[1],pict->data[2], pict->linesize[2]);// Set Size of Windowrect.x &#61; 0;rect.y &#61; 0;rect.w &#61; pCodecCtx->width;rect.h &#61; pCodecCtx->height;SDL_RenderClear(renderer);SDL_RenderCopy(renderer, texture, NULL, &rect);SDL_RenderPresent(renderer);}}// Free the packet that was allocated by av_read_frameav_free_packet(&packet);/*SDL_Event event;SDL_PollEvent(&event);switch(event.type) {case SDL_QUIT:goto __QUIT;break;default:break;}*/}__QUIT:ret &#61; 0;__FAIL:// Free the YUV frameif(pFrame){av_frame_free(&pFrame);}// Close the codecif(pCodecCtx){avcodec_close(pCodecCtx);}if(pCodecCtxOrig){avcodec_close(pCodecCtxOrig);}// Close the video fileif(pFormatCtx){avformat_close_input(&pFormatCtx);}if(pict){avpicture_free(pict);free(pict);}if(win){SDL_DestroyWindow(win);}if(renderer){SDL_DestroyRenderer(renderer);}if(texture){SDL_DestroyTexture(texture);}SDL_Quit();return ret;
}




推荐阅读
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
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社区 版权所有