標籤:
本文來自:http://blog.sina.com.cn/s/blog_4178f4bf01018wqh.html
最近幾天一直在折騰ffmpeg,在網上也查了許多資料,費了不少勁,現在在這裡和大家分享一下。
一、準備工作 本來是想自己在windows下編譯ffmpeg產生lib、dll等庫檔案的,但是折騰好久總是出錯,於是果斷放棄。幸好網上已經有了編譯好的版本,可以拿過來直接用,網址為http://ffmpeg.zeranoe.com/builds/。我們需要的是32-bit Builds (Shared)和32-bit Builds (Dev),版本號碼要相對應。32-bit Builds (Shared)主要包含了所要用到的dll檔案,32-bit Builds (Dev)主要包含了所要用的標頭檔和lib檔案。其實這些lib並不是傳統的靜態庫檔案(真正的靜態庫檔案是在lib目錄下的*.a檔案),他們是dll的匯出檔案。dll檔案在32-bit Builds (Shared)的bin目錄下,lib檔案在32-bit Builds (Dev)的lib目錄下,標頭檔在32-bit Builds (Dev)的include目錄下。 另外,C99中添加了幾個新的標頭檔,Visual Studio中沒有,所以需要你自己下載。並放至相應目錄。對於VS2010來說通常是:C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include。二、Visual Studio配置 在準備好庫檔案之後,便可以進行Visual Studio簡單的編譯工作了,下面給出一份當前可以編譯啟動並執行代碼,並以此為樣本。// ffmpeg-example.cpp : Defines the entry point for the console application.////#include "stdafx.h" #define inline _inline#ifndef INT64_C#define INT64_C(c) (c ## LL)#define UINT64_C(c) (c ## ULL)#endif #ifdef __cplusplusextern "C" {#endif #include <libavformat/avformat.h>#include <libavcodec/avcodec.h>#include <libswscale/swscale.h>#ifdef __cplusplus}#endif #include <stdio.h> static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame); int main (int argc, const char * argv[]){ AVFormatContext *pFormatCtx; int i, videoStream; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrame; AVFrame *pFrameRGB; AVPacket packet; int frameFinished; int numBytes; uint8_t *buffer; // Register all formats and codecs av_register_all(); // Open video file //if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)if(avformat_open_input(NULL, argv[1], NULL, NULL)!=0) return -1; // Couldn‘t open file // Retrieve stream information if(av_find_stream_info(pFormatCtx)<0) return -1; // Couldn‘t find stream information // Dump information about file onto standard error av_dump_format(pFormatCtx, 0, argv[1], false); // Find the first video stream videoStream=-1; for(i=0; i<pFormatCtx->nb_streams; i++) if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) { videoStream=i; break; } if(videoStream==-1) return -1; // Didn‘t find a video stream // Get a pointer to the codec context for the video stream pCodecCtx=pFormatCtx->streams[videoStream]->codec; // Find the decoder for the video stream pCodec=avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec==NULL) return -1; // Codec not found // Open codec if(avcodec_open(pCodecCtx, pCodec)<0) return -1; // Could not open codec // Hack to correct wrong frame rates that seem to be generated by some codecs if(pCodecCtx->time_base.num>1000 && pCodecCtx->time_base.den==1) pCodecCtx->time_base.den=1000; // Allocate video frame pFrame=avcodec_alloc_frame(); // Allocate an AVFrame structure pFrameRGB=avcodec_alloc_frame(); if(pFrameRGB==NULL) return -1; // Determine required buffer size and allocate buffer numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); //buffer=malloc(numBytes); buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); // Assign appropriate parts of buffer to image planes in pFrameRGB avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); // Read frames and save first five frames to disk i=0; while(av_read_frame(pFormatCtx, &packet)>=0) { // Is this a packet from the video stream? if(packet.stream_index==videoStream) { // Decode video frame avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); // Did we get a video frame? if(frameFinished) { static struct SwsContext *img_convert_ctx; #if 0 // Older removed code // Convert the image from its native format to RGB swscale img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); // function template, for reference int sws_scale(struct SwsContext *context, uint8_t* src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t* dst[], int dstStride[]);#endif // Convert the image into YUV format that SDL uses if(img_convert_ctx == NULL) { int w = pCodecCtx->width; int h = pCodecCtx->height; img_convert_ctx = sws_getContext(w, h, pCodecCtx->pix_fmt, w, h, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); if(img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context!\n"); exit(1); } } int ret = sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);#if 0 // this use to be true, as of 1/2009, but apparently it is no longer true in 3/2009 if(ret) { fprintf(stderr, "SWS_Scale failed [%d]!\n", ret); exit(-1); }#endif // Save the frame to disk if(i++<=5) SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i); } } // Free the packet that was allocated by av_read_frame av_free_packet(&packet); } // Free the RGB image //free(buffer); av_free(buffer); av_free(pFrameRGB); // Free the YUV frame av_free(pFrame); // Close the codec avcodec_close(pCodecCtx); // Close the video file av_close_input_file(pFormatCtx); return 0;} static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame){ FILE *pFile; char szFilename[32]; int y; // Open file sprintf(szFilename, "frame%d.ppm", iFrame); pFile=fopen(szFilename, "wb"); if(pFile==NULL) return; // Write header fprintf(pFile, "P6\n%d %d\n255\n", width, height); // Write pixel data for(y=0; y<height; y++) fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile); // Close file fclose(pFile);}首先在Visual Studio中建立工程,並將代碼添加到工程的.cpp檔案中。其次,就要配置工程的庫檔案和連結器。1. 設定ffmpeg標頭檔位置滑鼠右鍵點擊工程名,選擇屬性
然後選擇 配置屬性 -> C/C++ -> 常規 -> 附加元件封裝含目錄,添加目錄為你下載的32-bit Builds (Dev)中的標頭檔目錄。
2. 設定ffmpeg的lib檔案位置 滑鼠右鍵點擊工程名,選擇屬性, 然後選擇 配置屬性 -> 連結器 -> 常規 -> 附加庫目錄,添加目錄為你下載的32-bit Builds (Dev)中的lib檔案目錄。
3. 設定ffmpeg的所引用的lib檔案
滑鼠右鍵點擊工程名,選擇屬性, 然後選擇 配置屬性 -> 連結器 -> 輸入 -> 附加依賴項,添加的檔案為你下載的32-bit Builds (Dev)中的lib檔案。
如果一切正常,這時你便可以編譯成功。
三、可能出現的問題1. 雖然編譯通過,但是並不表示就可以運行,當你運行代碼時會出現以下錯誤
原因是,你雖然引用了LIB檔案,但這並不是真正的靜態庫檔案,而是對DLL的引用,所以當你調用ffmpeg庫函數時,需要DLL檔案在場。你可以用dumpbin(VS內建工具)來查看你產生的exe中引用了哪些DLL檔案。你在命令列輸入:>dumpbin D:\test\test.exe /imports然後根據顯示的檔案名稱,將下載的32-bit Builds (Shared)的bin檔案夾下的dll檔案拷貝到你建立的工程的源檔案目錄下。
2. 上段代碼中的變數argv[1],如果你沒有指定參數,則會報錯。所以如果不指定,則需要將其改為一個const char *的字串變數,字串內容為你想讀入的視頻的全路徑,例如const char* filename = "D:\\work\\code\\VideoConference\\test\\IMGP1816.AVI"; 上述都配置完畢就可以運行了,暫時先寫這麼多吧,後面我會繼續總結的。
在visual studio 2010中調用ffmpeg