C++ h264 ffmpeg/libav encode/decode(lossless) issues
Insights to encode/decode video with ffmpeg h264 (lossless)
So I got something working on the encoding part, encode an avi in 264 however VLC wont play it, however Totem will. Decoding the same file proves troublesome. (I want the exact same data/frame going in as going out), I get these ;
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
and ultimatly this
[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
GAME OVER.
Now I suspect that I have to go back to 1. the encoding part, there is problary a good reason VLC wont play it!
I encode like this.
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);
}
}
And the codec is setup like this:
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);
Since I am going for lossless i am not dealing with delayed frames(is this a correct assumption?) I may not actually be encoding lossless, it seems like I may have to go with something like
AVDictionary *param;
av_dict_set(¶m, "qp", "0", 0);
And then open...
So I guess me questions is these :
Thanks.
Some thing is seriously wrong in your encoding. The error "MV errors in I frame" is odd one here, there shouldn't be any MVs in I-frame. It seems the header parsing it-self gone wrong. Please share the bit-stream & more details for VLC failure
You're writing raw annexb frames into a file without any container wrapping. Use a container like mp4 or matroska and VLC should be happy.
So, got this one wrapped. Figured Id post my findings here as there is ALOT of semi valid-working information outthere.. Or maybe just working in circumstances different from mine, this is my code :
init code. - First thing to notice here is av_guess_format "avi" NOT "mp4" or anything else exotic for h264 - Second thing is, dont mess with bitrate!! This was driving me crazy as all samples I found online had it set. Leave it alone and control quality through "av_opt_set(ctx->priv_data, "crf", "0", 0);". When I had bitrate set the quality of the resulting encode would worsen over time until the frames was just a blur. - Third, use avio_open and avformat_write_header instead of jongling your own file handling.
// 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);
Encoding the live feed. I've left some code here uncommented for reviewing pleasure. According to docs this should be legal, catch up on delayed frames and carry on. Its not, so dont :), we will do that in the last bit when we close shop and write the trailer
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);
}
}
*/
}
And closing shop. - Write the delayed frames - Write trailer - Close stream :
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);
Hope this helps someone else kung-fu-googling outthere :).
链接地址: http://www.djcxy.com/p/67558.html