[FFmpeg-devel] [PATCH]: Fix decoding of mpegts streams with h264 video that does *NOT* have b frames
Tony Strauss
tony at animoto.com
Thu Apr 21 17:26:25 CEST 2011
Reposting, as I had the the ffmpeg-devel e-mail address wrong (was using the
old one)
On Tue, Apr 19, 2011 at 11:46 PM, Tony Strauss <tony at animoto.com> wrote:
> I'm cross-posting to ffmpeg-devel and libav-devel, as this issue
> exists in both codebases. I've attached the patch and reproduced
> below. I don't have a lot of experience with the ffmpeg code base.
>
> It originally was reported in:
> https://roundup.libav.org/issue2222
>
> The issue was created by the patch accepted in this e-mail thread:
> https://lists.ffmpeg.org/pipermail/ffmpeg-devel/2010-May/096245.html
>
> I ran across this issue because pts and dts were getting nuked by this
> block from utils.c for some of my mpegts files:
> if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE
> && presentation_delayed){
> av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination\n");
> pkt->dts= pkt->pts= AV_NOPTS_VALUE;
> }
>
> You can reproduce by running:
> ffprobe -loglevel debug -show_packets 720.no_b_frames.ts
>
> The test file may be downloaded from
> https://s3.amazonaws.com/tony-strauss-public/720.no_b_frames.ts. The
> key thing is that this file was encoded without b frames, so pts ==
> dts for every frame. has_b_frames, however, was getting incorrectly
> set by ffmpeg's h264 parser, which caused delay to be true and that
> block to be executed.
>
> Basically, the earlier patch made h264_parse() invoke
> ff_h264_decode_extradata() the first time through. The problem,
> however, is that the H264Context that was passed in belongs to the
> AVCodecParserContext and is uninitialized. In particular, low_delay =
> 0 and that eventually leads to has_b_frames = 1. My fix is to split
> off a new ff_h264_context_init() function from ff_h264_decode_init();
> this will initialize the AVCodecParserContext's H264Context and also
> invoke ff_h264_decode_extradata().
>
> The fix does not break ffmpeg's unit tests (I tried with those in
> libav; the ffmpeg tests seemed broken for unrelated reasons in the
> snapshot I tried) and fixes the dts/pts reported by ffprobe.
>
> Tony
>
> diff --git a/libavcodec/h264.c b/libavcodec/h264.c
> index dbf71a7..3062723 100644
> --- a/libavcodec/h264.c
> +++ b/libavcodec/h264.c
> @@ -868,6 +868,23 @@ av_cold int ff_h264_decode_init(AVCodecContext
> *avctx){
> H264Context *h= avctx->priv_data;
> MpegEncContext * const s = &h->s;
>
> + avctx->chroma_sample_location = AVCHROMA_LOC_LEFT;
> +
> + ff_h264_context_init(avctx, h);
> +
> + if(avctx->codec_id == CODEC_ID_H264){
> + if(avctx->ticks_per_frame == 1){
> + s->avctx->time_base.den *=2;
> + }
> + avctx->ticks_per_frame = 2;
> + }
> +
> + return 0;
> +}
> +
> +av_cold int ff_h264_context_init(AVCodecContext *avctx, H264Context *h){
> + MpegEncContext * const s = &h->s;
> +
> MPV_decode_defaults(s);
>
> s->avctx = avctx;
> @@ -880,9 +897,7 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx){
> // s->decode_mb= ff_h263_decode_mb;
> s->quarter_sample = 1;
> if(!avctx->has_b_frames)
> - s->low_delay= 1;
> -
> - avctx->chroma_sample_location = AVCHROMA_LOC_LEFT;
> + s->low_delay= 1;
>
> ff_h264_decode_init_vlc();
>
> @@ -891,18 +906,16 @@ av_cold int ff_h264_decode_init(AVCodecContext
> *avctx){
> h->prev_poc_msb= 1<<16;
> h->x264_build = -1;
> ff_h264_reset_sei(h);
> - if(avctx->codec_id == CODEC_ID_H264){
> - if(avctx->ticks_per_frame == 1){
> - s->avctx->time_base.den *=2;
> - }
> - avctx->ticks_per_frame = 2;
> - }
>
> if(avctx->extradata_size > 0 && avctx->extradata &&
> ff_h264_decode_extradata(h))
> return -1;
>
> if(h->sps.bitstream_restriction_flag && s->avctx->has_b_frames <
> h->sps.num_reorder_frames){
> + /*
> + * I'm a bit dubious about touching has_b_frames here, but
> + * has_b_frames usually is modified in tandem with low_delay.
> + */
> s->avctx->has_b_frames = h->sps.num_reorder_frames;
> s->low_delay = 0;
> }
> diff --git a/libavcodec/h264.h b/libavcodec/h264.h
> index 96720ac..caa13f6 100644
> --- a/libavcodec/h264.h
> +++ b/libavcodec/h264.h
> @@ -681,6 +681,7 @@ void ff_h264_hl_decode_mb(H264Context *h);
> int ff_h264_frame_start(H264Context *h);
> int ff_h264_decode_extradata(H264Context *h);
> av_cold int ff_h264_decode_init(AVCodecContext *avctx);
> +av_cold int ff_h264_context_init(AVCodecContext *avctx, H264Context *h);
> av_cold int ff_h264_decode_end(AVCodecContext *avctx);
> av_cold void ff_h264_decode_init_vlc(void);
>
> diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
> index 91fbebc..cdbf96a 100644
> --- a/libavcodec/h264_parser.c
> +++ b/libavcodec/h264_parser.c
> @@ -249,10 +249,7 @@ static int h264_parse(AVCodecParserContext *s,
>
> if (!h->got_first) {
> h->got_first = 1;
> - if (avctx->extradata_size) {
> - h->s.avctx = avctx;
> - ff_h264_decode_extradata(h);
> - }
> + ff_h264_context_init(avctx, h);
> }
>
> if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){
More information about the ffmpeg-devel
mailing list