【问题标题】:FFmpeg: generating H264 video in c++FFmpeg:在 C++ 中生成 H264 视频
【发布时间】:2016-01-11 01:48:06
【问题描述】:

我在带有 vs2012 的 windows 中使用 ffmpeg 库将一系列图像转换为具有 H264 编码的 Mp4。我是 FFMPEG 的新手。

下面是我的代码。一切都很顺利。视频已创建。但只有将扩展名更改为“.h264”时,我才能在 vlc 播放器中播放视频,而且当我检查编解码器信息时,它会显示“H264 - MPEG-4 AVC(第 10 部分)(h264)”。但是当我检查从网上下载的其他 mp4 视频时也是如此。它说“H264 - MPEG-4”AVC(第 10 部分)(avc1)“。我不明白哪里出错了。我也搜索了很多,有人说像添加 SPS 和 PPS。

const uint8_t sps[] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00,
0x0a, 0xf8, 0x41, 0xa2 };
const uint8_t pps[] = { 0x00, 0x00, 0x00, 0x01, 0x68, 0xce,
0x38, 0x80 };

所以我在添加图像流之前将上述值添加到视频文件中。但没有运气。 任何人都可以帮助解决这个问题。在此先感谢。

const uint8_t sps[] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00,
0x0a, 0xf8, 0x41, 0xa2 };
const uint8_t pps[] = { 0x00, 0x00, 0x00, 0x01, 0x68, 0xce,
0x38, 0x80 };
const uint8_t slice_header[] = { 0x00, 0x00, 0x00, 0x01, 0x05, 0x88,
0x84, 0x21, 0xa0 };
const uint8_t macroblock_header[] = { 0x0d, 0x00 };

const uint8_t spspps[] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x0a, 0xf8, 0x41, 0xa2, 
                           0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x38, 0x80
                         };

int ff_load_image(uint8_t *data[4], int linesize[4],
        int *w, int *h, enum PixelFormat *pix_fmt,
        const char *filename, void *log_ctx)
    {
        AVInputFormat *iformat = NULL;
        AVFormatContext *format_ctx = NULL;
        AVCodec *codec=NULL;
        AVCodecContext *codec_ctx=NULL;
        AVFrame *frame=NULL;
        int frame_decoded, ret = 0;
        AVPacket pkt;

        av_register_all();

        iformat = av_find_input_format("image2");
        if ((ret = avformat_open_input(&format_ctx, filename, iformat, NULL)) < 0) {
            return ret;
        }

        codec_ctx = format_ctx->streams[0]->codec;
        codec = avcodec_find_decoder(codec_ctx->codec_id);
        if (!codec) {
            ret = AVERROR(EINVAL);
            goto end;
        }

        if ((ret = avcodec_open2(codec_ctx, codec, NULL)) < 0) {
            goto end;
        }

        //if (!(frame = avcodec_alloc_frame()) ) {
        if (!(frame = av_frame_alloc()) ) {
            ret = AVERROR(ENOMEM);
            goto end;
        }

        ret = av_read_frame(format_ctx, &pkt);
        if (ret < 0) {
            goto end;
        }

        ret = avcodec_decode_video2(codec_ctx, frame, &frame_decoded, &pkt);
        if (ret < 0 || !frame_decoded) {
            goto end;
        }
        ret = 0;

        *w       = frame->width;
        *h       = frame->height;
        *pix_fmt = (PixelFormat)frame->format;

        if ((ret = av_image_alloc(data, linesize, *w, *h, (AVPixelFormat)*pix_fmt, 16)) < 0)
            goto end;
        ret = 0;

        av_image_copy(data, linesize, (const uint8_t **)frame->data, frame->linesize, (AVPixelFormat)*pix_fmt, *w, *h);

end:
        if(codec_ctx) { avcodec_close(codec_ctx); }
        if(format_ctx) { avformat_close_input(&format_ctx); }
        if(frame) { av_freep(&frame); }
        av_free_packet(&pkt);
                return ret;
    }

    int load_image_into_frame(AVFrame *frame, const char *filename)
    {
        int retval = -1, res;
        static struct SwsContext *sws_ctx;
        uint8_t *image_data[4];
        int linesize[4];
        int source_width, source_height;
        enum PixelFormat source_fmt;

        res = ff_load_image(image_data, linesize, &source_width, &source_height, &source_fmt, filename, NULL);

        if (source_fmt != frame->format) {
            sws_ctx = sws_getContext(source_width, source_height, (AVPixelFormat)source_fmt,
                frame->width, frame->height, (AVPixelFormat)frame->format,
                sws_flags, NULL, NULL, NULL);

            sws_scale(sws_ctx,
                (const uint8_t * const *)image_data, linesize,
                0, frame->height, frame->data, frame->linesize);
        }

        retval = 0;
error:
        av_freep(&image_data[0]);
        sws_freeContext(sws_ctx);
        return retval;
    }

    int write_frame_to_file(FILE *file, AVFrame *frame, AVCodecContext *codec_context, AVPacket *pkt) {
        int res, got_output;
        av_init_packet(pkt);
        pkt->data = NULL;
        pkt->size = 0;

        /* generate synthetic video */
        frame->pts += 30;

        res = avcodec_encode_video2(codec_context, pkt, frame, &got_output);

        if (got_output) {

            fwrite(pkt->data, 1, pkt->size, file);
            av_free_packet(pkt);
        }
        return 0;
error:
        return -1;
    }

    int write_image_to_file(FILE *file, const char *filename, int count, AVFrame *frame, AVCodecContext *codec_context, AVPacket *pkt) {
        int res, i;
        res = load_image_into_frame(frame, filename);

        for (i = 0; i < count; i++) {

            res = write_frame_to_file(file, frame, codec_context, pkt);
        }

        return 0;
error:
        return -1;
    }

    int write_delayed_frames_to_file(FILE *file, AVFrame *frame, AVCodecContext *codec_context, AVPacket *pkt) {
        int res, got_output;

        for (got_output = 1; got_output;) {
            res = avcodec_encode_video2(codec_context, pkt, NULL, &got_output);

            if (got_output) {
                fwrite(pkt->data, 1, pkt->size, file);
                av_free_packet(pkt);
            }
        }

        return 0;
error:
        return -1;
    }

    AVCodecContext *get_codec_context(int width, int height, int fps)
    {
        int res;
        avcodec_register_all();

        AVCodec *codec;
        AVCodecContext *codec_context = NULL;

        codec = avcodec_find_encoder(AV_CODEC_ID_H264);

        codec_context = avcodec_alloc_context3(codec);

        codec_context->bit_rate = 441000;
        codec_context->width = width;
        codec_context->height = height;
        AVRational temp_113 = {1, fps};
        AVRational temp_114 = {fps, 1};
        codec_context->time_base= temp_113;
        codec_context->gop_size = 10;
        codec_context->max_b_frames=1;
        codec_context->pix_fmt = AV_PIX_FMT_YUV420P;        

        res = avcodec_open2(codec_context, codec, NULL);

        return codec_context;
error:
        return NULL;
    }

    AVFrame *get_av_frame(AVCodecContext *codec_context) {
        int res;
        AVFrame *frame;

        frame = av_frame_alloc();
        frame->height = codec_context->height;
        frame->width = codec_context->width;
        frame->format = codec_context->pix_fmt;
        frame->pts = 0;

        res = av_image_alloc(frame->data, frame->linesize, frame->width, frame->height, (AVPixelFormat)frame->format, 1);

        return frame;
error:
        return NULL;
    }

    int main(int argc, char **argv)
    {
        const char *filename = "result video\\test.mp4";
        FILE *file=NULL;
        int res, retval=-1;
        AVCodecContext *codec_context= NULL;
        AVFrame *frame=NULL;
        AVPacket pkt;
        uint8_t endcode[] = { 0, 0, 1, 0xb7 };

        codec_context = get_codec_context(1920, 1080, 30);

        file = fopen(filename, "wb");
        //check(file != NULL, "could not open destination file %s", filename);

        frame = get_av_frame(codec_context);        

        //fwrite(sps, 1, sizeof(sps), file);
        //fwrite(pps, 1, sizeof(pps), file);

        /*codec_context->extradata = (uint8_t *)malloc(sizeof(uint8_t) * sizeof(spspps));

        for(unsigned int index = 0; index < sizeof(spspps); index++)
        {
            codec_context->extradata[index] = spspps[index];
        }

        codec_context->extradata_size = (int)sizeof(spspps);*/

        codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;

        int i, frames= 51;
        for (i = 0; i < frames; i++) {
            std::stringstream ss;
            ss<<"\\frames\\out"<<( i + 1)<<".jpg";
            res = write_image_to_file(file, ss.str().c_str(), 3, frame, codec_context, &pkt);
        }


        res = write_delayed_frames_to_file(file, frame, codec_context, &pkt);
        fwrite(endcode, 1, sizeof(endcode), file);

        retval = 0;
error:
        if (file)
            fclose(file);
        if (codec_context) {
            avcodec_close(codec_context);
            av_free(codec_context);
        }
        if (frame) {
            av_freep(&frame->data[0]);
            av_free(frame);
        }
        return retval;
    }
}

【问题讨论】:

    标签: c++ video ffmpeg


    【解决方案1】:

    您没有使用 AVFormatContext 进行编码,因此我看到了您无法按需要输出 .mp4 文件的原因。

    你应该:

    1. 使用 AVFormatContext
    2. 直接或使用avformat_alloc_output_context2() 之类的函数将AVOutputFormat 设置为AVFormatContext->oformat(输出格式)
    3. 可选:必要时设置标志并调用avio_open2() 访问资源。
    4. 致电avformat_write_header()

    我会发布代码,但是网上有很多示例,您可以通过将这些函数名称与“ffmpeg 编码”关键字混合使用来找到这些示例。

    【讨论】:

    • 感谢您的回复:-)。你的建议很有用。我有一些像你说的例子,但他们不允许我将像素数据写入文件。我应该调用函数“av_interleaved_write_frame()”。此函数在内部将 AVPacket 写入输出文件。但我的要求是获取视频缓冲区,它不应该直接写入文件。
    猜你喜欢
    • 2015-02-23
    • 2012-08-03
    • 2016-10-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 2019-12-05
    • 2017-07-20
    • 2012-09-28
    相关资源
    最近更新 更多