結合系列教程http://dranger.com/ffmpeg/tutorial01.html把ffmpeg,SDL和教程在linux平臺下用GCC編譯,並加入調試參數,已達到能編譯後所有源碼都能用gdb跟蹤的效果。網頁上有很多教程都是使用VC或者mingui的,而且用的是已經編好的ffmpeg和SDL的庫來編譯,這樣的好處是免去了一些編譯的步驟和時間,但是卻不能讓我們可以自己跟蹤ffmpeg和SDL的源碼。爲了能結合跟蹤這些源碼,用ffmpeg和SDL的源碼以及教程的調用代碼來編譯一個工程,這裏結合我自己的操作,一步一步列出從簡單到複雜的綜合編譯過程,也希望能在這個過程重拾對Makefile的理解。
1. 首先建立目錄ffmpeg和SDL,分別下載ffmpeg和SDL(http://www.libsdl.org/download-1.2.php)的源碼。在ffmpeg裏運行
./configure --disable-yasm
make
在SDL目錄裏運行
./configure
make
生成的庫libSDL.a和libSDLmain.a在SDL/build/.libs目錄下。
2. 建立與ffmpeg和SDL同級的目錄simulation, 在simulation下建立src, include, out, obj這四個目錄,並把tutorial01.c放在src目錄下。具體的目錄結構如下:
---ffmpeg
---SDL
---simulation
--------src
--------include
--------obj
--------Makefile
3. 由於tutorial01.c對應的ffmpeg的版本有些舊,有些宏定義和API的名字需要修改,如下:
#include "avcodec.h" ---> #include "libavcodec/avcodec.h"
#include "avformat.h" ---> #include "libavformat/avformat.h"
CODEC_TYPE_VIDEO ---> AVMEDIA_TYPE_VIDEO
if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0) --->
if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
dump_format(pFormatCtx, 0, argv[1], 0); ---> av_dump_format(pFormatCtx, 0, argv[1], 0);
avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size); --->
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
運行編譯命令:
gcc -g -o tu ./src/tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lm -I../ffmpeg
出現一下編譯報錯信息:
tutorial01.c:(.text+0x378): undefined reference to `img_convert'
這時由於新版的ffmpeg已經用swscale來取代了運來舊版的img_convert函數導致的,因此,進行下面4的修改。
4.對tutorial01.c增加一下內容
#include "libswscale/swscale.h"
#include "libswscale/swscale_internal.h"
int img_convert(AVPicture *dst, int dst_pix_fmt,
const AVPicture *src, int src_pix_fmt,
int src_width, int src_height)
{
int w;
int h;
SwsContext *pSwsCtx;
w = src_width;
h = src_height;
pSwsCtx = sws_getContext(w, h, src_pix_fmt,
w, h, dst_pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(pSwsCtx, src->data, src->linesize,
0, h, dst->data, dst->linesize);
//這裏釋放掉pSwsCtx的內存
return 0;
}
上面是用新版的API接口重寫了img_convert函數。另外,由於用到了libswscale庫,必須在編譯命令里加 -lswscale, 用下面的命令編譯:
gcc -g -o tu ./src/tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lswscale -lm -I../ffmpeg
編譯報錯:
/home/liaowm/workspace/iPlayer/jni/ffmpeg/libavformat/udp.c:657: undefined reference to `pthread_cancel'
/home/liaowm/workspace/iPlayer/jni/ffmpeg/libavformat/udp.c:658: undefined reference to `pthread_join'
/usr/local/lib/libavformat.a(udp.o): In function `udp_open':
/home/liaowm/workspace/iPlayer/jni/ffmpeg/libavformat/udp.c:545: undefined reference to `pthread_create'
/usr/local/lib/libavcodec.a(pthread.o): In function `frame_thread_free':
/home/liaowm/workspace/iPlayer/jni/ffmpeg/libavcodec/pthread.c:756: undefined reference to `pthread_join'
/usr/local/lib/libavcodec.a(pthread.o): In function `thread_free':
/home/liaowm/workspace/iPlayer/jni/ffmpeg/libavcodec/pthread.c:251: undefined reference to `pthread_join'
/usr/local/lib/libavcodec.a(pthread.o): In function `frame_thread_init':
/home/liaowm/workspace/iPlayer/jni/ffmpeg/libavcodec/pthread.c:873: undefined reference to `pthread_create'
/usr/local/lib/libavcodec.a(pthread.o): In function `thread_init':
/home/liaowm/workspace/iPlayer/jni/ffmpeg/libavcodec/pthread.c:339: undefined reference to `pthread_create'
是由於沒有鏈接到pthread相關的庫造成的,因此,再次修改編譯命令,增加 -lpthread, 如下:
gcc -g -o tu ./src/tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lswscale -lpthread -lm -I../ffmpeg
編譯通過。
5. 運行程序
./tu test.avi
出現段錯誤報錯,用gdb 調試, 發現錯誤報告如下:
Program received signal SIGSEGV, Segmentation fault.
init_input (ps=0x7fffffffe2d0, filename=0x7fffffffe720 "/home/liaowm/workspace/iPlayer/jni/simulation/test_stream/352x240_H263_MP3_0_24_CiKeLianMeng.flv",
fmt=<value optimized out>, options=0x0) at libavformat/utils.c:537
537 s->flags |= AVFMT_FLAG_CUSTOM_IO;
查閱了下網絡,段錯誤一般是由於對非法地址(超出程序空間)引起的,而這些代碼應該是沒有這種明顯的bug的,所以有可能是由於動態庫和靜態庫之間空間的使用差別引起的,所以,對ffmpeg添加 --enable-static參數進行重新編譯和安裝,再重新編譯程序:
cd ../ffmpeg
./configure --disable-yasm --enable-static
make; make install
gcc -g -o tu ./src/tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lpthread -lswscale -lm -I../ffmpeg
再重新運行,解碼正確,輸出了5個RGB圖片:frame1.ppm ~ frame5.ppm, 用display或其他圖形工具可以看到。
再接下來的一章,我們會繼續嘗試用一個簡單的Makefile來完善這個工程。