[SimplePlayer] 1. 从视频文件中提取图像

在开始之前,我们需要了解视频文件的格式。视频文件的格式众多,无法三言两语就能详细分析其结构,尽管如此,ffmpeg却很好地提取了各类视频文件的共同特性,并对其进行了抽象描述。

image

视频文件格式,统称为container。它包含一个描述视频信息的头部,以及内含实际的音视频编码数据的packets。当然,这里的头部以及packet部分只是个抽象描述,实际的视频格式的描述信息可能不是存放在视频文件的起始位置,可能是由分散于视频文件的各个位置的多个部分组成;数据包有可能是由头部以及尾部进行分割的传统数据包形式,也有可能是一大块数据区域,由索引进行各个数据包的分割。

视频文件中的packets最主要的就是视频以及音频packets,demux的过程就是解析container的header来获取视频信息,所得到的视频信息能帮助我们区分packet是音频或者视频。同样属性的packets会被称为stream。

packet中存储的数据就是音视频编码后的数据,通过解码器进行decode后就能得到视频图像或者音频帧。其中需要注意的一点是,一个packet不一定对应一帧,packet的顺序也不一定是实际的播放顺序,而通过ffmpeg解码出来的frame的顺序就是实际的播放顺序。

 

Demux

首先需要一个用于存储视频文件信息的结构体。

pFormatCtx = avformat_alloc_context();

 

读取视频文件,并对该文件进行demux,所得到的视频信息存储于刚刚所构建的结构体当中

    if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0){fprintf(stderr, "open input failed\n");return -1;}

如果pFormatCtx=NULL,那么avformat_open_input也能自动为pFormatCtx分配存储空间。

 

对于有些视频格式,单单通过demux并不能获得所有的视频信息,为了获得这些信息,还需要读取并尝试解码该视频几个最前端packets(通常会解码每个stream第一个packet)。所读取的这几个packets会被缓存以供后续处理。

if(avformat_find_stream_info(pFormatCtx, NULL)<0){fprintf(stderr, "find stream info failed\n");return -1;}

 

从所获得的信息当中得到video stream序号,后续可以通过stream序号来对packet进行筛选。

videoStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

 

 

Decode

创建一个用于存储以及维护解码信息结构体。

pCodecCtx = avcodec_alloc_context3(NULL);

 

把demux时所获得的视频相关信息传递到解码结构体中。

if(avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar)<0){fprintf(stderr, "copy param from format context to codec context failed\n");return -1;}

 

根据解码器id来寻找对应的解码器

pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if(pCodec==NULL){fprintf(stderr, "Unsupported codec,codec id %d\n", pCodecCtx->codec_id);return -1;}else{fprintf(stdout, "codec id is %d\n", pCodecCtx->codec_id);}

 

打开该解码器,主要目的是对解码器进行初始化

    if(avcodec_open2(pCodecCtx, pCodec, NULL)<0){fprintf(stderr, "open codec failed\n");return -1;}

 

创建一个用于维护所读取的packet的结构体,一个用于维护解码所得的frame的结构体

    pPacket = av_packet_alloc();pFrame = av_frame_alloc();if(pFrame == NULL||pPacket == NULL){fprintf(stderr, "cannot get buffer of frame or packet\n");return -1;}

 

从视频文件中读取packet,如果所读取的packet是video,则进行解码,解码所得的帧由pFrame进行维护。当然,并不是每次调用avcodec_decode_video2都会返回一帧,因为也可能会有需要多个packet才能解码出一帧的情况,因此只有当指示一帧是否解码完成的frameFinished为1才能对这一帧进行后续处理。

    while(av_read_frame(pFormatCtx, pPacket)>=0){//Only deal with the video stream of the type "videoStream"if(pPacket->stream_index==videoStream){//Decode video frameavcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, pPacket);//fprintf(stdout, "Frame : %d ,pts=%lld, timebase=%lf\n", i, pFrame->pts, av_q2d(pFormatCtx->streams[videoStream]->time_base));if(frameFinished){if(i>=START_FRAME && i<=END_FRAME){SaveFrame2YUV(pFrame, pCodecCtx->width, pCodecCtx->height, i);i++;}else{i++;continue;}}}av_packet_unref(pPacket);}

当一个packet被解码后就可以调用av_packet_unref来释放该packet所占用的空间了。

 

 

Store

视频文件解码出来后通常都是YUV格式,Y、U、V三路分量分别存储在AVFrame的data[0]、data[1]、data[2]所指向的内存区域。linesize[0]、linesize[1]、linesize[2]分别指示了Y、U、V一行所占用的字节数。下面把解码所得的帧保存为YUV Planar格式。

void SaveFrame2YUV(AVFrame *pFrame, int width, int height, int iFrame){static FILE *pFile;char szFilename[32];int y;//Open fileif(iFrame==START_FRAME){sprintf(szFilename, "Video.yuv");pFile = fopen(szFilename, "wb");if(pFile==NULL)return;}//Write YUV Data, Only support YUV420//Yfor(y=0; y<height; y++){fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, pFrame->linesize[0], pFile);}//Ufor(y=0; y<(height+1)/2; y++){fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, pFrame->linesize[1], pFile);}//Vfor(y=0; y<(height+1)/2; y++){fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, pFrame->linesize[2], pFile);}//Close FIleif(iFrame==END_FRAME){fclose(pFile);}
}

 

 

最后就是释放内存,关闭decoder,关闭demuxer

    av_free(pPacket);av_free(pFrame);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);

转载于:https://www.cnblogs.com/TaigaCon/p/9603854.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/426904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实例21:python

#猴子吃桃问题&#xff1a;猴子第一天摘下若干个桃子&#xff0c; #当即吃了一半&#xff0c;还不瘾&#xff0c;又多吃了一个第二天早上又将剩下的桃子吃掉一半&#xff0c; #又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。 #到第10天早上想再吃时&#xff0c;见只…

android5.1 显示方向,Android5.1 Settings.apk定制显示选项

在Android5.0后&#xff0c;系统应用的目录结构发生了一些变化&#xff0c;以往/system/app/下直接是APK文件&#xff0c;目前是/system/app/应用名目录/应用apk类似这种目录结构。同时在Android5.1上反编译Settings.apk需要使用最新apktool_2.0.3来反编译&#xff0c;否则无法…

实例22:python

#题目&#xff1a;两个乒乓球队进行比赛&#xff0c;各出三人。甲队为a,b,c三人&#xff0c; #乙队为x,y,z三人。已抽签决定比赛名单。 #有人向队员打听比赛的名单。a说他不和x比&#xff0c;c说他不和x,z比&#xff0c;请编程序找出三队赛手的名单。 #!/usr/bin/python -- c…

CCF 201312-3 最大的矩形[比较简单]

问题描述 试题编号&#xff1a;201312-3试题名称&#xff1a;最大的矩形时间限制&#xff1a;1.0s内存限制&#xff1a;256.0MB问题描述&#xff1a; 问题描述在横轴上放了n个相邻的矩形&#xff0c;每个矩形的宽度是1&#xff0c;而第i&#xff08;1 ≤ i ≤ n&#xff09;个矩…

实例23:python

#题目&#xff1a;打印出如下图案&#xff08;菱形&#xff09;: * *** ***** #******* ***** *** * #先把图形分成两部分来看待&#xff0c;前四行一个规律&#xff0c;后三行一个规律&#xff0c;利用双重for循环&#xff0c;第一层控制行&#xff0c;第二层控制列。…

android 滚动尺画到控件中间,android 刻度尺控件实现

主要实现刻度尺的效果&#xff0c;能够快速滑动刻度&#xff0c;设置刻度间距&#xff0c;刻度值&#xff0c;滑动回调。简单易用效果图textureView控件的选择总结来说:1.view的绘制在主线程里面&#xff0c;频繁绘制会导致主线程阻塞2.我们知道一个surfaceview是异步绘制的&am…

实例24:python

#题目&#xff1a;有一分数序列&#xff1a;2/1&#xff0c;3/2&#xff0c;5/3&#xff0c;8/5&#xff0c;13/8&#xff0c;21/13…求出这个数列的前20项之和。 #!/usr/bin/python -- coding: UTF-8 -- a 2.0 b 1.0 s 0 for n in range(1,21): s a / b t a a a b b…

Luogu 4514 上帝造题的七分钟

二维差分树状数组。 定义差分数组$d_{i, j} a_{i, j} a_{i - 1, j - 1} - a_{i, j - 1} - a_{i - 1, j}$&#xff0c;有$a_{i, j} \sum_{x 1}^{i}\sum_{y 1}^{j}d_{i, j}$。 我们要求$sum(n, m) \sum_{i 1}^{n}\sum_{j 1}^{m}a_{i, j} $&#xff0c; 代入$a_{i, j}$&am…

实例25:python

#题目&#xff1a;求12!3!…20!的和。 #!/usr/bin/python -- coding: UTF-8 -- n 0 s 0 t 1 for n in range(1,21): t * n s t print (‘1! 2! 3! … 20! %d’ % s)

实例26:python

#题目&#xff1a;利用递归方法求5! #!/usr/bin/python -- coding: UTF-8 -- def fact(j):#定义一个函数 sum 0 if j 0: sum 1 else: sum j * fact(j - 1) return sum print (fact(5))

[SimplePlayer] 2. 在屏幕上显示视频图像

我们这里采用SDL&#xff08;本文所用版本为SDL2.0.5&#xff09;来进行图像输出&#xff0c;SDL在进行图像渲染时一般采用的会是direct3D或者opengl&#xff0c;SDL对它们进行了封装&#xff0c;不过我们这里只讨论SDL的使用&#xff0c;并不会去涉及这些底层实现。尽管如此&a…

实例27:python

#题目&#xff1a;利用递归函数调用方式&#xff0c;将所输入的5个字符&#xff0c;以相反顺序打印出来。 #函数赋值两个变量 def output(s,l): if l0: return print (s[l-1]) output(s,l-1) s input(‘Input a string:’) l len(s) output(s,l)

《React Native跨平台移动应用开发》PDF电子书分享

链接: https://pan.baidu.com/s/14r6xZPJ0u1mrZejEuV8RrA 密码: pqan 分享《React Native跨平台移动应用开发》PDF电子书&#xff0c;本书为高清PDF电子书&#xff0c;内容截图如下 转载于:https://www.cnblogs.com/meidongdiluo/p/9625607.html

实例28:python

#题目&#xff1a;有5个人坐在一起&#xff0c;问第五个人多少岁&#xff1f;他说比第4个人大2岁。 #问第4个人岁数&#xff0c;他说比第3个人大2岁。问第三个人&#xff0c;又说比第2人大两岁。 #问第2个人&#xff0c;说比第一个人大两岁。最后问第一个人&#xff0c;他说是1…

如何使用vs2017进行html开发,VS2017开发vue单页应用

我正在学vue开发&#xff0c;想用VS开发一个单页应用&#xff0c;按照网上的提示配置好了&#xff0c;但是始终无法运行起来&#xff0c;主要有以下两点&#xff1a;在main.js中使用了import Vue from vue&#xff0c;但是实际运行时提示 import 错误无法安装npm包&#xff0c;…

实例29:python

#题目&#xff1a;给一个不多于5位的正整数&#xff0c;要求&#xff1a;一、求它是几位数&#xff0c;二、逆序打印出各位数字 #!/usr/bin/python -- coding: UTF-8 -- x int(input(“请输入一个数:\n”)) a x / 10000 b x % 10000 / 1000 c x % 1000 / 100 d x % 100…

2021届定远三中高考成绩查询,定远各中学高考喜报!

原标题&#xff1a;定远各中学高考喜报&#xff01;关注定远2019年高考实现多项新突破本科达线人数较上年增加340人(点击看大图)砥砺前行新时代&#xff0c;定远教育写华章。6月23日&#xff0c;全县人民高度关注的2019年高考成绩揭晓。我县教体系统广大师生不负众望&#xff0…

实例30:python

#一个5位数&#xff0c;判断它是不是回文数。即12321是回文数&#xff0c; #个位与万位相同&#xff0c;十位与千位相同。 x int(input(‘输入一个五位数&#xff1a;’)) a int(x / 10000) b int(x % 10000 / 1000) c int(x % 1000 / 100) d int(x % 100 / 10) e int(x …

实例31:python

#题目&#xff1a;请输入星期几的第一个字母来判断一下是星期几 #!/usr/bin/python -- coding: UTF-8 -- letter input(“please input:”) #while letter ! ‘Y’: if letter ‘S’: print (‘please input second letter:’) letter input(“please input:”) if lette…

实例32:python

#按相反的顺序输出列表的值。 #!/usr/bin/python -- coding: UTF-8 -- a [‘one’, ‘two’, ‘three’] for i in a[::-1]: print (i)