-1

AVFrameピクセルが一度に 1 つのチャネルを行優先の順序で格納される配列にコピーしようとしています。

詳細:

ビデオからフレームを読み取るために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] である必要があります。問題は、配列がフレームを一度に 1 つのチャネル、つまり R11、R12、... R21、R22、... G11、G12、... G21、G22、などの行優先順で格納する必要があることです。 . B11, B12, ... B21, B22, ... ([カラー チャネル][行インデックス][列インデックス] という表記を使用しました。つまり、G21 は行 2、列 1 のピクセルの緑チャネル値です) . 私は を見てきましたが、sws_scaleその関数がそのような変換を行うことができるかどうかを理解するのに十分ではありません. 誰か助けてくれませんか!! :)

4

1 に答える 1

1

あなたが「一度に 1 つのチャネル」と呼んだ形式には、という用語がありplanarます。(ちなみに、反対の形式は と呼ばれますpacked)そして、ほとんどすべてのピクセル形式は行順です。

ここでの問題は、入力形式が異なる場合があり、すべてを 1 つの形式に変換する必要があることです。それsws_scale()がそうです。

ただし、planar RGBffmpeg ライブラリにはまだそのような形式はありません。独自のピクセル形式の記述を 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)
于 2016-12-19T04:11:39.313 に答える