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的源碼。所以這個疑問還望有知情人解答。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章