<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    ffmpeg 從內存中讀取數據(或將數據輸出到內存)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    更新記錄(2014.7.24):

    1.為了使本文更通俗易懂,更新了部分內容,將例子改為從內存中打開。

    2.增加了將數據輸出到內存的方法。

     

    從內存中讀取數據

    ffmpeg一般情況下支持打開一個本地文件,例如“C:\test.avi”

    或者是一個流媒體協議的URL,例如“rtmp://222.31.64.208/vod/test.flv”

    其打開文件的函數是avformat_open_input(),直接將文件路徑或者流媒體URL的字符串傳遞給該函數就可以了。

    但其是否支持從內存中讀取數據呢?這個問題困擾了我很長時間。當時在做項目的時候,通過Winpcap抓取網絡上的RTP包,打算直接送給ffmpeg進行解碼。一直沒能找到合適的方法。因為抓取的數據包是存在內存中的,所以無法傳遞給avformat_open_input()函數其路徑(根本沒有路徑= =)。當然也可以將抓取的數據報存成文件,然后用ffmpeg打開這個文件,但是這樣的話,程序的就太難控制了。

    后來經過分析ffmpeg的源代碼,發現其竟然是可以從內存中讀取數據的,代碼很簡單,如下所示:

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. AVFormatContext *ic = NULL;  
    2. ic = avformat_alloc_context();  

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. unsigned char * iobuffer=(unsigned char *)av_malloc(32768);  
    2. AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,NULL,fill_iobuffer,NULL,NULL);  
    3. ic->pb=avio;  
    4. err = avformat_open_input(&ic, "nothing", NULL, NULL);  


    關鍵要在avformat_open_input()之前初始化一個AVIOContext,而且將原本的AVFormatContext的指針pb(AVIOContext類型)指向這個自行初始化AVIOContext。當自行指定了AVIOContext之后,avformat_open_input()里面的URL參數就不起作用了。示例代碼開辟了一塊空間iobuffer作為AVIOContext的緩存。

     

    fill_iobuffer則是將數據讀取至iobuffer的回調函數。fill_iobuffer()形式(參數,返回值)是固定的,是一個回調函數,如下所示(只是個例子,具體怎么讀取數據可以自行設計)。示例中回調函數將文件中的內容通過fread()讀入內存。

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. //讀取數據的回調函數-------------------------  
    2. //AVIOContext使用的回調函數!  
    3. //注意:返回值是讀取的字節數  
    4. //手動初始化AVIOContext只需要兩個東西:內容來源的buffer,和讀取這個Buffer到FFmpeg中的函數  
    5. //回調函數,功能就是:把buf_size字節數據送入buf即可  
    6. //第一個參數(void *opaque)一般情況下可以不用  
    7. int fill_iobuffer(void * opaque,uint8_t *buf, int bufsize){  
    8.     if(!feof(fp_open)){  
    9.         int true_size=fread(buf,1,buf_size,fp_open);  
    10.         return true_size;  
    11.     }else{  
    12.         return -1;  
    13.     }  
    14. }  



     

    整體結構大致如下:

     

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. FILE *fp_open;  
    2.   
    3. int fill_iobuffer(void *opaque, uint8_t *buf, int buf_size){  
    4. ...  
    5. }  
    6.   
    7. int main(){  
    8.     ...  
    9.     fp_open=fopen("test.h264","rb+");  
    10.     AVFormatContext *ic = NULL;  
    11.     ic = avformat_alloc_context();  
    12.     unsigned char * iobuffer=(unsigned char *)av_malloc(32768);  
    13.     AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,NULL,fill_iobuffer,NULL,NULL);  
    14.     ic->pb=avio;  
    15.     err = avformat_open_input(&ic, "nothing", NULL, NULL);  
    16.     ...//解碼  
    17. }  



    將數據輸出到內存

     

    和從內存中讀取數據類似,ffmpeg也可以將處理后的數據輸出到內存。

    回調函數如下示例,可以將輸出到內存的數據寫入到文件中。

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
    1. //寫文件的回調函數  
    2. int write_buffer(void *opaque, uint8_t *buf, int buf_size){  
    3.     if(!feof(fp_write)){  
    4.         int true_size=fwrite(buf,1,buf_size,fp_write);  
    5.         return true_size;  
    6.     }else{  
    7.         return -1;  
    8.     }  
    9. }  

     

     

    主函數如下所示。

     

    [cpp] view plaincopy在CODE上查看代碼片派生到我的代碼片  
      1. FILE *fp_write;  
      2.   
      3. int write_buffer(void *opaque, uint8_t *buf, int buf_size){  
      4. ...  
      5. }  
      6.   
      7. main(){  
      8.     ...  
      9.     fp_write=fopen("src01.h264","wb+"); //輸出文件  
      10.     ...  
      11.     AVFormatContext* ofmt_ctx=NULL;  
      12.     avformat_alloc_output_context2(&ofmt_ctx, NULL, "h264", NULL);  
      13.     unsigned char* outbuffer=(unsigned char*)av_malloc(32768);  
      14.   
      15.     AVIOContext *avio_out =avio_alloc_context(outbuffer, 32768,0,NULL,NULL,write_buffer,NULL);    
      16.   
      17.     ofmt_ctx->pb=avio_out;   
      18.     ofmt_ctx->flags=AVFMT_FLAG_CUSTOM_IO;  
      19.     ...  
      20. }  
    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全