2016-12-17 48 views
-1

ピクセルは行優先順位で一度に1チャンネルずつ格納される配列にAVFrameをコピーすることを検討しています。FFMPEG - チャンネルごとのアレイ変換へのAVFrame

詳細:

私はビデオからフレームを読み取るためにFFMPEGのAPIを使用しています。私はframe_arr、ピクセルの範囲にvid_frameの全てをコピーする必要が

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

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 */ 
     } 
    } 
} 

宛先アレイは次のようになります。次のように私はAVFrameように、各フレームを取得するためにavcodec_decode_video2を使用しています値は[0、255]でなければなりません。問題は、アレイが一度に1つのチャネル、つまりR11、R12、... R21、R22、... G11、G12、...、G21、G22、...の順番で行を格納する必要があることです。 B11、B12、... B21、B22、...(私は表記[カラーチャンネル] [行インデックス] [列インデックス]を使用しました。つまりG21は行2の1列目のピクセルの緑色チャンネル値で​​す) 。私はsws_scaleを見ましたが、その機能がそのような変換を行うことができるかどうかを知るには十分理解できません。誰かが助けることができます! :)

答えて

1

「一度に1つのチャンネル」と呼ばれるフォーマットは、planarという名前です。 (btw、反対のフォーマットはpackedと命名されています)そして、ほとんどすべてのピクセル形式は行順です。

ここで問題となるのは入力形式が異なることがあり、すべてが1つの形式に変換されることです。それはsws_scale()の機能です。

しかし、まだffmpegライブラリにplanar RGBという形式はありません。 ffmpegのソースコードlibavutil/pixdesc.cに独自のピクセル形式の記述を書いて、libsを再構築する必要があります。

またはフレームを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

関連する問題