C ++ h264 ffmpeg / libav编码/解码(无损)问题

洞察使用ffmpeg h264编码/解码视频(无损)

所以我在编码部分做了一些工作,在264中编码了一个AVI,但VLC不会播放它,但图腾会。 解码相同的文件证明麻烦。 (我想要完全相同的数据/框架出去),我得到这些;

saving frame   5
Video decoding
[h264 @ 0x1d19880] decode_slice_header error
frame :6
saving frame   6
Video decoding
[h264 @ 0x1d19880] error while decoding MB 15 7, bytestream -27
[h264 @ 0x1d19880] concealing 194 DC, 194 AC, 194 MV errors in I frame
frame :7
saving frame   7
Video decoding
[h264 @ 0x1d19880] decode_slice_header error

并最终达成此目的

[H264 Decoder @ 0x7f1320766040] frame :11
Broken frame packetizing
[h264 @ 0x1d19880] SPS changed in the middle of the frame
[h264 @ 0x1d19880] decode_slice_header error
[h264 @ 0x1d19880] no frame!
Error while decoding frame 11

游戏结束。

现在我怀疑我必须回到1.编码部分,有证据证明VLC不会播放它!

我这样编码。

void encode(char *Y,char *U,char *V){
av_init_packet(&pkt);
pkt.data = NULL;    // packet data will be allocated by the encoder
pkt.size = 0;
fflush(stdout);

frame->data[0] = (uint8_t*)Y;
frame->data[1] = (uint8_t*)U;
frame->data[2] = (uint8_t*)V;
frame->pts = ++i;

ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
    fprintf(stderr, "Error encoding framen");
    exit (EXIT_FAILURE);
}
if (got_output) {
    printf("Write frame %3d (size=%5d)n", i, pkt.size);
    fwrite(pkt.data, 1, pkt.size, f);
    av_free_packet(&pkt);
}
}

编解码器是这样设置的:

AVCodecID dasd = AV_CODEC_ID_H264;
codec = avcodec_find_encoder(dasd);
c = avcodec_alloc_context3(codec);
c->bit_rate = 400000;
c->width = 320;
c->height = 240;
c->time_base= (AVRational){1,25};
c->gop_size = 10; 
c->max_b_frames=1;
c->pix_fmt = AV_PIX_FMT_YUV420P;
av_opt_set(c->priv_data, "preset", "slow", 0);
avcodec_open2(c, codec, NULL);

由于我是无损的,我没有处理延迟帧(这是一个正确的假设吗?)我可能实际上没有编码无损,看起来像我可能不得不采取类似

AVDictionary *param;
av_dict_set(&param, "qp", "0", 0);

然后打开...

所以我想我的问题是这些:

  • 什么是无损编码的正确编解码参数(如果h264在这方面是一个可怕的想法,那么建议是什么)。
  • 无损时,我需要处理延迟帧吗?
  • 为什么VLC对我生气?
  • 谢谢。


  • 实现无损:av_dict_set(&param,“crf”,“0”,0);
  • 延迟帧(B帧)与无损无关。 如果您需要低延迟,则不要使用B帧。
  • 有些东西在你的编码中是严重错误的。 错误“I帧中的MV错误”在这里是奇怪的,在I帧中不应该有任何MV。 它似乎解析它的头 - 自己出错了。 请分享VLC失败的比特流和更多细节


    您正在将原始附件帧写入文件而没有任何容器包装。 使用像mp4或matroska容器和VLC应该很高兴。


    所以,得到这个包裹。 因为在这里有很多半有效工作信息,或者只是在不同于我的情况下工作,这是我的代码:

    init代码。 - 这里首先要注意的是av_guess_format“avi”不是“mp4”或其他什么奇异的h264 - 第二件事是,不要乱用比特率! 随着我在网上找到的所有样本都设置好了,这让我发疯。 保持独立并通过“av_opt_set(ctx-> priv_data,”crf“,”0“,0);”来控制质量。 当我设置了比特率时,编码的质量会随着时间的推移而恶化,直到帧变得模糊。 第三,使用avio_open和avformat_write_header,而不是使用自己的文件处理。

    // av_log_set_level(AV_LOG_DEBUG);
    av_register_all();
    avcodec_register_all();
    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); //
    AVOutputFormat * outputFormat = av_guess_format("avi", NULL, NULL);
    outFmtCtx = NULL;
    int test = avformat_alloc_output_context2(&outFmtCtx, outputFormat, NULL, NULL);
    if(test<0) exit(-1);
    avstream = avformat_new_stream(outFmtCtx, codec);
    avstream->time_base= (AVRational){1,25};;
    
    
    avcodec_get_context_defaults3(avstream->codec, codec);
    AVCodecContext *ctx = avstream->codec;
    
    // ctx->bit_rate = 1000000; // messing with this POS is just gonna get you brainpain .. dont do it man..
    ctx->width = 320;
    ctx->height = 240;
    //ctx->time_base= (AVRational){1,25};
    ctx->gop_size = 10; /* emit one intra frame every ten frames */
    ctx->max_b_frames=10;
    ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    
    // FOR H264 ONLY
    av_opt_set(ctx->priv_data, "preset", "slow", 0);
    // av_opt_set(ctx->priv_data, "crf", "0", 0);  // 17 megs for 35 secs ... without : 900k
    
    // FOR H264 ONLY
    
    test = av_opt_set(avstream->codec->priv_data, "preset", "slow", 0);
    if(test<0) exit(-2);
    test = avcodec_open2(avstream->codec, codec, NULL);
    if(test<0) exit(-3);
    test = avio_open2(&outFmtCtx->pb, filenamhen, AVIO_FLAG_WRITE, NULL, NULL);
    if(test<0) exit(-4);
    
    test = avformat_write_header(outFmtCtx, NULL);
    if(test<0) exit(-5);
    frame = avcodec_alloc_frame();
    if (!frame) exit(-6);
    
    frame->format = avstream->codec->pix_fmt;
    frame->width  = avstream->codec->width;
    frame->height = avstream->codec->height;
    
    ret = av_image_alloc(frame->data, frame->linesize, frame->width, frame->height, avstream->codec->pix_fmt, 32);
    if (ret < 0) exit(-7);
    

    编码实时馈送。 我在这里留下了一些未注释的代码来审查快乐。 根据文件,这应该是合法的,赶上延迟帧并继续。 它不是,所以不要:),当我们关闭商店并写预告片时,我们会在最后一点做到这一点

    pkt.data = NULL;
    pkt.size = 0;
    av_init_packet(&pkt);
    
    frame->data[0] = (uint8_t*)Y;
    frame->data[1] = (uint8_t*)U;
    frame->data[2] = (uint8_t*)V;
    frame->pts = i;
    
    ret = avcodec_encode_video2(avstream->codec, &pkt, frame, &got_output);
    if (ret < 0) {
        fprintf(stderr, "Error encoding framen");
        exit (EXIT_FAILURE);
    }
    if (got_output) {
        printf("Write frame %3d (size=%5d)n", i, pkt.size);
        //fwrite(pkt.data, 1, pkt.size, file_encoded_video);
        // av_write_frame(outFmtCtx, &pkt);
        av_interleaved_write_frame(outFmtCtx, &pkt);
        av_free_packet(&pkt);
    }
    /*
    for (got_output = 1; got_output; i++) {
        fflush(stdout);
        ret = avcodec_encode_video2(avstream->codec, &pkt, NULL, &got_output);
        if (ret < 0) {
            fprintf(stderr, "Error encoding framen");
            exit(1);
        }
    
        if (got_output) {
            printf("Write dealyed frame %3d (size=%5d)n", i, pkt.size);
            // av_write_frame(outFmtCtx, &pkt);
            av_interleaved_write_frame(outFmtCtx, &pkt);
            av_free_packet(&pkt);
        }
    }
    */
    

    }

    并关闭店铺。 - 写延迟帧 - 写预告片 - 关闭流:

    pkt.data = NULL;
    pkt.size = 0;
    av_init_packet(&pkt);
    for (got_output = 1; got_output; i++) {
            fflush(stdout);
            ret = avcodec_encode_video2(avstream->codec, &pkt, NULL, &got_output);
            if (ret < 0) {
                fprintf(stderr, "Error encoding framen");
                exit(1);
            }
    
            if (got_output) {
                printf("Write dealyed frame %3d (size=%5d)n", i, pkt.size);
                // av_write_frame(outFmtCtx, &pkt);
                av_interleaved_write_frame(outFmtCtx, &pkt);
                av_free_packet(&pkt);
            }
        }
    av_write_trailer(outFmtCtx);
    avio_close(outFmtCtx->pb);
    

    希望这可以帮助其他人功夫谷歌搜索:)。

    链接地址: http://www.djcxy.com/p/67557.html

    上一篇: C++ h264 ffmpeg/libav encode/decode(lossless) issues

    下一篇: Decoding H264 Frame Error