在linux下聯合編譯ffmpeg和SDL源碼之一

        結合系列教程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來完善這個工程。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章