2016-12-17 71 views
-1

我正在尋找將AVFrame複製到一個數組中,其中像素以一個主要的順序一次存儲一個通道。FFMPEG - AVFrame到每個通道陣列的轉換

詳情:

我使用FFmpeg的API來讀取從視頻幀。我已經使用avcodec_decode_video2每一幀取作爲AVFrame如下:

AVFormatContext* fmt_ctx = NULL; 
avformat_open_input(&fmt_ctx, filepath, NULL, NULL); 
... 
int video_stream_idx; // stores the stream index for the video 
... 
AVFrame* vid_frame = NULL; 
vid_frame = av_frame_alloc(); 
AVPacket vid_pckt; 
int frame_finish; 
... 
while (av_read_frame(fmt_ctx, &vid_pckt) >= 0) { 
    if (b_vid_pckt.stream_index == video_stream_idx) { 
     avcodec_decode_video2(cdc_ctx, vid_frame, &frame_finish, &vid_pckt); 
     if (frame_finish) { 
      /* perform conversion */ 
     } 
    } 
} 

目的地陣列看起來像這樣:

unsigned char* frame_arr = new unsigned char [cdc_ctx->width * cdc_ctx->height * 3]; 

我需要所有的vid_frame複製到frame_arr,像素的其中該範圍值應該是[0,255]。問題在於陣列需要按行的主要順序存儲幀,一次一個通道,即R11,R12,... R21,R22,... G11,G12,... G21,G22,...。 (我已經使用了符號[顏色通道] [行索引] [列索引],即G21是第2行第1列中的像素的綠色通道值)B11,B12,... B21,B22,... 。我曾看過sws_scale,但我不明白這足以確定該功能是否有能力進行此類轉換。有人可以幫助! :)

回答

1

您稱爲「一次一個通道」的格式有一個名爲planar的術語。 (順便說一句,相反的格式被命名爲packed)幾乎所有的像素格式都是行順序的。

這裏的問題是輸入格式可能會有所不同,它們都應該轉換爲一種格式。這就是sws_scale()所做的。

但是,在ffmpeg庫中還沒有這樣的planar RGB格式。您必須將自己的像素格式描述寫入ffmpeg源代碼libavutil/pixdesc.c並重新構建庫。

或者你可以將幀轉換成AV_PIX_FMT_GBRP格式,這與你想要的格式最相似。 AV_PIX_FMT_GBRP是一種平面格式,而綠色通道最初是紅色,最後是紅色(藍色中間)。然後重新排列這些頻道。

// Create a SwsContext first: 
SwsContext* sws_ctx = sws_getContext(cdc_ctx->width, cdc_ctx->height, cdc_ctx->pix_fmt, cdc_ctx->width, cdc_ctx->height, AV_PIX_FMT_GBRP, 0, 0, 0, 0); 
// alloc some new space for storing converted frame 
AVFrame* gbr_frame = av_frame_alloc(); 
picture->format = AV_PIX_FMT_GBRP; 
picture->width = cdc_ctx->width; 
picture->height = cdc_ctx->height; 
av_frame_get_buffer(picture, 32); 
.... 

while (av_read_frame(fmt_ctx, &vid_pckt) >=0) { 
    ret = avcodec_send_packet(cdc_ctx, &vid_pckt); 
    // In particular, we don't expect AVERROR(EAGAIN), because we read all 
    // decoded frames with avcodec_receive_frame() until done. 
    if (ret < 0) 
     break; 

    ret = avcodec_receive_frame(cdc_ctx, vid_frame); 
    if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) 
     break; 
    if (ret >= 0) { 
     // convert image from native format to planar GBR 
     sws_scale(sws_ctx, vid_frame->data, 
        vid_frame->linesize, 0, vid_frame->height, 
        gbr_frame->data, gbr_frame->linesize); 

     // rearrange gbr channels in gbr_frame as you like 
     // g channel is gbr_frame->data[0] 
     // b channel is gbr_frame->data[1] 
     // r channel is gbr_frame->data[2] 
     // ...... 
    } 
} 

av_frame_free(gbr_frame); 
av_frame_free(vid_frame); 
sws_freeContext(sws_ctx); 
avformat_free_context(fmt_ctx) 
+0

謝謝@halfelf。我做了一些初始測試,看起來像使用sws_scale轉換爲GBR相當慢,而不是逐個像素地複製。我會報告回來! – ahmadh