An ffmpeg and SDL Tutorial在ffmpeg-1.0.1上的更新,tutorial01

 
An ffmpeg and SDL Tutorialffmpeg-1.0.1上的更新
 
Tutorial01
 
本篇是整个系列的基础,详细介绍了ffmpeg的整个工作流程,以及重要的数据结构。Sample code实现了将视频中的前5帧图像提取出来另存为PPM文件。流程非常清晰,没有太多困难的地方,我们直接改代码。
 
更新
Line22, 23
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
改为
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
Ffmpeg-1.0.1中,头文件已经分类到各个库单独的文件夹中,所以需指定其所在目录。
 
Line50
AVFormatContext *pFormatCtx;
改为
AVFormatContext *pFormatCtx = NULL;
后续与avformat_open_input()函数一起说明。
 
Line69
if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
    return -1; // Couldn't open file
改为
if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
    return -1; // Couldn't open file
ffmpeg-1.0.1中,函数av_open_input_file()已经完全被avformat_open_input()取代。前两个参数没变,分别是AVFormatContext结构和通过命令行参数传入的媒体文件文件名。后两个参数暂未深究,可能传入NULL ffmpeg会自动处理。
这里重点说一下AVFormatContext结构,它是整个程序中贯穿始终的一个数据结构,可以理解为整个编解码环境的上下文,它包含了其他一些很重要的数据结构。注意AVFormatContext根据不同的应用场景其初始化过程会有差异的分步完成。当把它的地址作为参数传入avformat_open_input()时,如果之前pFormatCtx没有分配空间,必须将其赋为NULL,否则将造成段错误。这也是第50行所作修改的原因。
 
Line77
dump_format(pFormatCtx, 0, argv[1], 0);
改为
av_dump_format(pFormatCtx, 0, argv[1], 0);
ffmpeg-1.0.1中,函数dump_format()变更为av_dump_format(),功能不变。
 
Line82
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
改为
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
ffmpeg-1.0.1codec_type的类型变更。
 
Line127
avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
              packet.data, packet.size);
改为
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,
              &packet);
ffmpeg-1.0.1中,函数avcodec_decode_video()avcodec_decode_video2()替换,原本avcodec_decode_video()中的第4个参数packet.data和第5个参数packet.size直接改成填入packet地址即可。
 
Line133
img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24,
            (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width,
            pCodecCtx->height);
改为
static struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
ffmpeg-1.0.1中,img_convert()被一种更准确更高效的方法——sws_scale()替代。其实tutorial08专门解释了这个改变,这里只是给出了一个简化写法。当然,别忘了#include <libswscale/swscale.h>
 
好了,编译执行吧。以下是我的编译脚本,这么简单一玩意儿咱也犯不着去make了。你的目录结构可能和我不尽相同,请自己修改。源文件可直接从附件中得到。http://cutebunny.blog.51cto.com/blog/301216/1121847
 
#!/bin/sh
 
FFMPEG_ROOT="ffmpeg-1.0.1"
 
gcc $1 -g -o sample -I../$FFMPEG_ROOT \
-L../$FFMPEG_ROOT/libavformat -L../$FFMPEG_ROOT/libavcodec -L../$FFMPEG_ROOT/libavutil -L../$FFMPEG_ROOT/libswscale \
-lavformat -lavcodec -lswscale -lavutil -lz -lbz2 -lm –lpthread
 
 
解释
Q:
为什么同样是AVFramepFramepFrameRGB都经过了avcodec_alloc_frame()分配空间,pFrame直接拿来用,而pFrameRGB却要再用avpicture_fill()填入一个buffer
A:
gdb跟一下,观察pFrame->datapFrame->linesize,发现在avcodec_decode_video2()过程中自动分配了空间,
之前
(gdb) print *pFrame
$5 = {data = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, linesize = {0, 0, 0, 0,
    0, 0, 0, 0},
之后
(gdb) print *pFrame
$6 = {data = {0xa7c2bf0 '\020' <repeats 200 times>...,
    0xa832830 '\200' <repeats 200 times>...,
    0xa84f070 '\200' <repeats 200 times>..., 0x0, 0x0, 0x0, 0x0, 0x0},
 linesize = {768, 384, 384, 0, 0, 0, 0, 0},
pFrameRGB并没有decode的过程,它只是用来存储将原始的pFrame转换为RGB格式的帧,所以需要手动分配其存储空间。
 
疑问
Q:
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame?
if(frameFinished) {
……
}
上述代码中在avcodec_decode_video2()后会进行framefinished的判断。在tutorial的说明中,先提到Technically a packet can contain partial frames or other bits of data, but ffmpeg's parser ensures that the packets we get contain either complete or
multiple frames. 可是随后又说,However, we might not have all the information
we need for a frame after decoding a packet, so avcodec_decode_video() sets
frameFinished for us when we have the next frame. 是不是看上去有点矛盾?到底一个Packet能不能包含一个或多个完整的帧?我只是从一个C Programmer的角度去使用ffmpeg,并没有深入理解编解码的规范和ffmpeg的源码。所以这个疑问还望有知情人解答。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章