【问题标题】:Using libavcodec to read .mkv video file使用 libavcodec 读取 .mkv 视频文件
【发布时间】:2020-06-22 01:03:21
【问题描述】:

尝试读取 .mkv 文件并将其写入 .bmp,但生成的 .bmp 是黑白的,并且包含多个应该写入的迷你图像:

int main()
{
    av_register_all();
    avformat_network_init();
    avfilter_register_all();

    //crashes on -Ofast without =NULL initialization:
    AVFormatContext * format = NULL;
    if ( avformat_open_input( & format, VIDEO_FILE, NULL, NULL ) != 0 ) {
        cerr << "Could not open file " << VIDEO_FILE << endl;
        return -1;
    }

    // Retrieve stream information
    if ( avformat_find_stream_info( format, NULL ) < 0) {
        cerr << "avformat_find_stream_info() failed." << endl;
        return -1;
    }
    av_dump_format( format, 0, VIDEO_FILE, false );

    AVCodec * video_dec = (AVCodec*)1;
    AVCodec * audio_dec = (AVCodec*)1;
    const auto video_stream_index = av_find_best_stream( format, AVMEDIA_TYPE_VIDEO, -1, -1, & video_dec, 0 );
    const auto audio_stream_index = av_find_best_stream( format, AVMEDIA_TYPE_AUDIO, -1, -1, & audio_dec, 0 );
    if ( video_stream_index < 0 ) {
        cerr << "Failed to find video stream." << endl;
        return -1;
    }
    if ( audio_stream_index < 0 ) {
        cerr << "Failed to find audio stream." << endl;
        return -1;
    }

    AVCodecParameters * videoParams = format->streams[ video_stream_index ]->codecpar;
    cout << "Having " << videoParams->width << " | " << videoParams->height << " video." << endl;

    av_read_play( format );

    // create decoding context
    AVCodecContext * video_ctx = avcodec_alloc_context3( video_dec );
    AVCodecContext * audio_ctx = avcodec_alloc_context3( audio_dec );
    if ( ! video_ctx || ! audio_ctx ) {
        cerr << "Failed to avcodec_alloc_context3()" << endl;
        return -1;
    }
    if ( video_dec->capabilities & AV_CODEC_CAP_TRUNCATED ) video_ctx->flags |= AV_CODEC_FLAG_TRUNCATED; // we do not send complete frames

    /* For some codecs, such as msmpeg4 and mpeg4, width and height
       MUST be initialized there because this information is not
       available in the bitstream. */

    avcodec_parameters_to_context( video_ctx, format->streams[ video_stream_index ]->codecpar );
    avcodec_parameters_to_context( audio_ctx, format->streams[ audio_stream_index ]->codecpar );
    if ( avcodec_open2( video_ctx, video_dec, NULL ) < 0 ) {
        cout << "Failed to open video decoder." << endl;
        return -1;
    }
    if ( avcodec_open2( audio_ctx, audio_dec, NULL ) < 0 ) {
        cout << "Failed to open audio decoder." << endl;
        return -1;
    }

    uint8_t* picture_buffer = (uint8_t*) (av_malloc( avpicture_get_size( AV_PIX_FMT_RGB24 , videoParams->width, videoParams->height ) ));
    AVFrame* picture = av_frame_alloc();
    avpicture_fill( (AVPicture *) picture, picture_buffer, AV_PIX_FMT_RGB24, video_ctx->width, video_ctx->height );

    AVPacket packet;
    av_init_packet( & packet );

    int cnt = 0;
    while ( av_read_frame( format, & packet ) >= 0 && cnt < 10 ) {
        if ( packet.stream_index == video_stream_index ) {
            int check;
            const auto result = avcodec_decode_video2( video_ctx, picture, & check, & packet );
            cout << "Bytes decoded " << result << " check " << check << endl;

            std::string name = "debug/av/";
            name += std::to_string( cnt ) + ".bmp";
            cout << "Writing frame " << name << " with linesize " << picture->linesize[0] << " ..." << endl;
            write_bmp( (uint8_t*) picture->data, videoParams->width, videoParams->height, name.c_str() );

            av_frame_unref( picture );

            ++ cnt;
        }
        else if ( packet.stream_index == audio_stream_index ) {
            cout << "Sound packet" << endl;
        }
        av_free_packet( & packet );
        av_init_packet( & packet );
    }
}

我该如何解决?

【问题讨论】:

    标签: ffmpeg libav libavcodec libavformat


    【解决方案1】:

    您必须使用 swscale 将图片转换为 RGB。

    【讨论】:

    • 感谢您的回答!据我了解,图像是 AV_PIX_FMT_YUV420P 格式,但我该如何将其转换为 RGB?有没有办法以编程方式确定帧格式以便任何视频文件都可以工作?
    • 是的,请查看 AVFrame 的文档。它有一个可以传递给 swscale 的格式值。 swscale 也有很好的文档,在互联网上有很多例子。
    • 不,我尝试使用大约 10 个 libav 示例,但都失败了,主要是由于我的 Ubuntu 18.04 和内核 v5.4 libav 我猜太现代了。例如,this sample 我走得最远:它至少可以编译,但给出[mpeg1video @ 0x55ded11f97e0] Invalid frame dimensions 0x0. 错误:(
    • 所以,目前正在尝试调整来自 herehere 的样本来为 swsscale() 构造 AVFrame 但得到 swscaler: bad src image pointers 错误.
    • ... 以及使用实用函数av_image_alloc() like this 初始化 AVFrame 的另一次尝试(不记得我在哪里找到它)在 if() 内部失败。
    猜你喜欢
    • 2010-11-11
    • 2020-07-27
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 2015-03-08
    • 1970-01-01
    • 2014-04-30
    • 2019-01-21
    相关资源
    最近更新 更多