ffmpeg 內存讀寫相關


需要的解碼的視頻數據在一段內存中。例如,通過其他系統送來的視頻數據。同樣,有的時候編碼后的視頻數據也未必要保存成一個文件。例如,要求將編碼后的視頻數據送給其他的系統進行下一步的處理。以上兩種情況就要求FFmpeg不僅僅是對文件進行“讀,寫”操作,而是要對內存進行“讀,寫”操作。
從內存中讀取數據
經過 分析ffmpeg的源代碼 ,發現其是可以從內存中讀取數據的:
  1. AVFormatContext *ic = NULL;  
  2. ic = avformat_alloc_context();  
  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() 讀入內存
  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. }  
整體結構大致如下:
  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. }  
將數據輸出到內存
也可以將處理后的數據輸出到內存。
回調函數如下示例,可以將輸出到內存的數據寫入到文件中。
  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. }  
主函數如下所示。
  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. }  
關鍵點
關鍵點就兩個:
1.      初始化自定義的AVIOContext,指定自定義的回調函數。示例代碼如下:
  1. //AVIOContext中的緩存  
  2. unsigned char *aviobuffer=(unsigned char*)av_malloc(32768);  
  3. AVIOContext *avio=avio_alloc_context(aviobuffer, 32768,0,NULL,read_buffer,NULL,NULL);  
  4. pFormatCtx->pb=avio;  
  5.    
  6. if(avformat_open_input(&pFormatCtx,NULL,NULL,NULL)!=0){  
  7.            printf("Couldn't open inputstream.(無法打開輸入流)\n");  
  8.            return -1;  
  9. }  
上述代碼中,自定義了回調函數read_buffer()。在使用avformat_open_input()打開媒體數據的時候,就可以不指定文件的URL了,即其 第2個參數為NULL (因為數據不是靠文件讀取,而是由read_buffer()提供)
2.      自己寫回調函數。示例代碼如下:
  1. //Callback  
  2. int read_buffer(void *opaque, uint8_t *buf, int buf_size){  
  3.     if(!feof(fp_open)){  
  4.         int true_size=fread(buf,1,buf_size,fp_open);  
  5.         return true_size;  
  6.     }else{  
  7.         return -1;  
  8.     }  
  9. }  
當系統需要數據的時候, 會自動調用 該回調函數以獲取數據。 這個例子為了簡單,直接使用fread()讀取數據至內存。回調函數需要 格外注意 它的參數和返回值。
avio_alloc_context第3個參數 Set to 1 if the buffer should be writable, 0 otherwise. 為0時表示ffmpeg要從回調函數里 讀取 數據。為1表示ffmpeg會將數據輸出到回調函數中。
參考:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM