ffmpeg 重寫tutorial01程序--將一個視頻文件解碼輸出bmp和jpg文件

參考鏈接1:Compile LibJPEG
參考鏈接2:利用ffmpeg0.5 和libjpeg實現抽取視頻幀並將其保存爲jpeg文件格式程序
參考鏈接3:ffmpeg 重寫tutorial01程序--將一個視頻文件解碼輸出ppm文件或bmp文件

之前寫過一個將視頻文件解碼輸出bitmap文件(見參考鏈接3),由於項目需要,需要輸出jpg文件,由於jpg格式是有損壓縮的,比bmp格式要複雜許多,簡單google下,libjpeg開源庫正合我意,使用起來簡單清晰,網上很多朋友提供了很好的例子,我在windows7下編譯花費了較多的時間。

操作系統: windows 7 旗艦版
開發環境:vs2008
相關庫:ffmpeg,libjpeg

vs工程文件

1. 編譯libjpeg
以前編譯ffmpeg受過傷,想偷個懶,想想這麼通用的庫,網上提供的的.lib應該很多的,google "libjpeg for windows",第一條就提供了相應的庫,大喜,用之,而事實上,正是因爲自己的拿來主義,導致我後面遇到了各種莫名奇妙的問題,在執行jpeg_wirte_scanlines()和jpeg_finish_compress()時出現"寫入位置發生訪問衝突",由於是編譯好的lib庫,無法單步調試到相關函數裏面檢查錯誤,這個問題讓人很絕望。


網上google時,無意找到了Compile LibJPEG看看,似乎編譯過程也並不複雜,報着最後一絲希望,決定自己編譯下libjpeg。該文已經將編譯過程寫得很詳細了,我在windows7下編譯也沒有任何問題。下面我做一個簡單的翻譯。
1.1 從 http://www.ijg.org/files/上下載jpegsrc.v6b.tar.gz。
1.2 解壓,假設我們放在C:\temp\jpegsrc.v6b下。
1.3 重命名c:\jpegsrc.v6b\jpeg-6b\makefile.vc 爲 c:\jpegsrc.v6b\jpeg-6b\Makefile。
1.4 重命名c:\jpegsrc.v6b\jpeg-6b\jconfig.vc 爲 c:\jpegsrc.v6b\jpeg-6b\jconfig.h。
1.5 打開cmd(快捷鍵:win+r)
1.6 在cmd中運行如下命令。vsvars32.bat的位置可能會不同,結合自己情況修改。注意:""不能少
  • "C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
  • cd C:\temp\jpegsrc.v6b\jpeg-6b
  • nmake -f Makefile
1.7 編譯成功後,在C:\temp\jpegsrc.v6b\jpeg-6b下會生成一個libjpeg.lib文件
1.8 對C:\temp\jpegsrc.v6b\jpeg-6b\jmorecfg.h進行修改:

/* INT32 must hold at least signed 32-bit values. */
#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */
typedef long INT32;
#endif
and make it look like this:
// INT32 must hold at least signed 32-bit values. 
//#ifndef XMD_H                 // X11/xmd.h correctly defines INT32 
#if !defined( XMD_H ) && !defined( WIN32 )
typedef long INT32;
#endif
1.9 對C:\temp\jpegsrc.v6b\jpeg-6b\jmorecfg.h進行修改:

#ifdef NEED_FAR_POINTERS
#define FAR far
#else
#define FAR
#endif
and make it look like this:

#ifdef NEED_FAR_POINTERS
#define FAR far
#else
#undef FAR // Added by Linden Lab to remove warnings
#define FAR
#endif
1.10 將
"jconfig.h"
"jerror.h"
"jinclude.h"
"jmorecfg.h"
"jpeglib.h"
以及
jpegliblib
添加到你的vs2008工程文件中

2. 使用libjpeg
由於libjpeg是C語言寫的,在包含jpeglib.h時需要加上

extern "C" {
#include "jpeglib.h"
}

3. 部分源代碼
#include <windows.h>

extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include "jpeglib.h" // for jpeglib
};

//實現視頻幀的jpeg壓縮
void saveAsJpeg(AVFrame *pFrameRGBint widthint heightint framenum)
{
      char fname[128];
      // AVPicture my_pic ;
      struct jpeg_compress_struct cinfo;
      struct jpeg_error_mgr jerr;
      JSAMPROW row_pointer[1];
      int row_stride;
      uint8_t *buffer;
      FILE *fp = NULL;

      buffer = pFrameRGB->data[0];

      int size = sizeof(buffer);

      cinfo.err = jpeg_std_error(&jerr);
      jpeg_create_compress(&cinfo);

      //_snprintf(fname, sizeof(fname), "frames%d.jpg", framenum);
      sprintf(fname"frames%d.jpg"framenum);
      fp = fopen(fname"wb");

      if (fp == NULL)
            return;

      jpeg_stdio_dest(&cinfofp);

      cinfo.image_width = width;
      cinfo.image_height = height;
      cinfo.input_components = 3;
      cinfo.in_color_space = JCS_RGB;

      jpeg_set_defaults(&cinfo);

      jpeg_set_quality(&cinfo, 80, true);

      jpeg_start_compress(&cinfoTRUE);

      row_stride = width * 3;

      while (cinfo.next_scanline < height)
      {
            /* jpeg_write_scanlines expects an array of pointers to scanlines.
            * Here the array is only one element long, but you could pass
            * more than one scanline at a time if that's more convenient.
            */
            row_pointer[0] = &buffer[cinfo.next_scanline * row_stride];
            jpeg_write_scanlines(&cinforow_pointer, 1);
      }

      jpeg_finish_compress(&cinfo);
      fclose(fp);
      jpeg_destroy_compress(&cinfo);
      printf("compress %d frame finished!\n",framenum) ;
      return ;

}












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