Merge commit 'b9589f5a770ec2357ab7920a5fabe8510b8601f9'
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 30 Oct 2013 09:13:23 +0000 (10:13 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 30 Oct 2013 09:23:24 +0000 (10:23 +0100)
* commit 'b9589f5a770ec2357ab7920a5fabe8510b8601f9':
  lavc: add error checking to apply_param_change.

Conflicts:
libavcodec/utils.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/utils.c

@@@ -1922,39 -1321,7 +1922,39 @@@ int avcodec_encode_subtitle(AVCodecCont
      return ret;
  }
  
- static void apply_param_change(AVCodecContext *avctx, AVPacket *avpkt)
 +/**
 + * Attempt to guess proper monotonic timestamps for decoded video frames
 + * which might have incorrect times. Input timestamps may wrap around, in
 + * which case the output will as well.
 + *
 + * @param pts the pts field of the decoded AVPacket, as passed through
 + * AVFrame.pkt_pts
 + * @param dts the dts field of the decoded AVPacket
 + * @return one of the input values, may be AV_NOPTS_VALUE
 + */
 +static int64_t guess_correct_pts(AVCodecContext *ctx,
 +                                 int64_t reordered_pts, int64_t dts)
 +{
 +    int64_t pts = AV_NOPTS_VALUE;
 +
 +    if (dts != AV_NOPTS_VALUE) {
 +        ctx->pts_correction_num_faulty_dts += dts <= ctx->pts_correction_last_dts;
 +        ctx->pts_correction_last_dts = dts;
 +    }
 +    if (reordered_pts != AV_NOPTS_VALUE) {
 +        ctx->pts_correction_num_faulty_pts += reordered_pts <= ctx->pts_correction_last_pts;
 +        ctx->pts_correction_last_pts = reordered_pts;
 +    }
 +    if ((ctx->pts_correction_num_faulty_pts<=ctx->pts_correction_num_faulty_dts || dts == AV_NOPTS_VALUE)
 +       && reordered_pts != AV_NOPTS_VALUE)
 +        pts = reordered_pts;
 +    else
 +        pts = dts;
 +
 +    return pts;
 +}
 +
+ static int apply_param_change(AVCodecContext *avctx, AVPacket *avpkt)
  {
      int size = 0;
      const uint8_t *data;
          avcodec_set_dimensions(avctx, avctx->width, avctx->height);
          size -= 8;
      }
+     return 0;
+ fail:
+     av_log(avctx, AV_LOG_ERROR, "PARAM_CHANGE side data too small.\n");
+     return AVERROR_INVALIDDATA;
  }
  
 +static int add_metadata_from_side_data(AVCodecContext *avctx, AVFrame *frame)
 +{
 +    int size, ret = 0;
 +    const uint8_t *side_metadata;
 +    const uint8_t *end;
 +
 +    side_metadata = av_packet_get_side_data(avctx->pkt,
 +                                            AV_PKT_DATA_STRINGS_METADATA, &size);
 +    if (!side_metadata)
 +        goto end;
 +    end = side_metadata + size;
 +    if (size && end[-1])
 +        return AVERROR_INVALIDDATA;
 +    while (side_metadata < end) {
 +        const uint8_t *key = side_metadata;
 +        const uint8_t *val = side_metadata + strlen(key) + 1;
 +        int ret;
 +
 +        if (val >= end)
 +            return AVERROR_INVALIDDATA;
 +
 +        ret = av_dict_set(avpriv_frame_get_metadatap(frame), key, val, 0);
 +        if (ret < 0)
 +            break;
 +        side_metadata = val + strlen(val) + 1;
 +    }
 +end:
 +    return ret;
 +}
 +
  int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
                                                int *got_picture_ptr,
 -                                              AVPacket *avpkt)
 +                                              const AVPacket *avpkt)
  {
      AVCodecInternal *avci = avctx->internal;
      int ret;
          av_frame_unref(&avci->to_free);
  
      if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
-         apply_param_change(avctx, &tmp);
 +        int did_split = av_packet_split_side_data(&tmp);
++        ret = apply_param_change(avctx, &tmp);
++        if (ret < 0) {
++            av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
++            if (avctx->err_recognition & AV_EF_EXPLODE)
++                goto fail;
++        }
++
 +        avctx->pkt = &tmp;
          if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
              ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,
 -                                         avpkt);
 +                                         &tmp);
          else {
              ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
 -                                       avpkt);
 +                                       &tmp);
              picture->pkt_dts = avpkt->dts;
 +
 +            if(!avctx->has_b_frames){
 +                av_frame_set_pkt_pos(picture, avpkt->pos);
 +            }
 +            //FIXME these should be under if(!avctx->has_b_frames)
              /* get_buffer is supposed to set frame parameters */
              if (!(avctx->codec->capabilities & CODEC_CAP_DR1)) {
 -                picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
 -                picture->width               = avctx->width;
 -                picture->height              = avctx->height;
 -                picture->format              = avctx->pix_fmt;
 +                if (!picture->sample_aspect_ratio.num)    picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
 +                if (!picture->width)                      picture->width               = avctx->width;
 +                if (!picture->height)                     picture->height              = avctx->height;
 +                if (picture->format == AV_PIX_FMT_NONE)   picture->format              = avctx->pix_fmt;
              }
          }
 +        add_metadata_from_side_data(avctx, picture);
  
++fail:
          emms_c(); //needed to avoid an emms_c() call before every return;
  
 +        avctx->pkt = NULL;
 +        if (did_split) {
 +            av_packet_free_side_data(&tmp);
 +            if(ret == tmp.size)
 +                ret = avpkt->size;
 +        }
 +
          if (ret < 0 && picture->data[0])
              av_frame_unref(picture);
  
@@@ -2188,102 -1471,14 +2208,107 @@@ int attribute_align_arg avcodec_decode_
      if (!avctx->refcounted_frames)
          av_frame_unref(&avci->to_free);
  
 -    if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size) {
 -        ret = avctx->codec->decode(avctx, frame, got_frame_ptr, avpkt);
 +    if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
 +        uint8_t *side;
 +        int side_size;
 +        uint32_t discard_padding = 0;
 +        // copy to ensure we do not change avpkt
 +        AVPacket tmp = *avpkt;
 +        int did_split = av_packet_split_side_data(&tmp);
-         apply_param_change(avctx, &tmp);
++        ret = apply_param_change(avctx, &tmp);
++        if (ret < 0) {
++            av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
++            if (avctx->err_recognition & AV_EF_EXPLODE)
++                goto fail;
++        }
 +
 +        avctx->pkt = &tmp;
 +        if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
 +            ret = ff_thread_decode_frame(avctx, frame, got_frame_ptr, &tmp);
 +        else {
 +            ret = avctx->codec->decode(avctx, frame, got_frame_ptr, &tmp);
 +            frame->pkt_dts = avpkt->dts;
 +        }
          if (ret >= 0 && *got_frame_ptr) {
 +            add_metadata_from_side_data(avctx, frame);
              avctx->frame_number++;
 -            frame->pkt_dts = avpkt->dts;
 +            av_frame_set_best_effort_timestamp(frame,
 +                                               guess_correct_pts(avctx,
 +                                                                 frame->pkt_pts,
 +                                                                 frame->pkt_dts));
              if (frame->format == AV_SAMPLE_FMT_NONE)
                  frame->format = avctx->sample_fmt;
 +            if (!frame->channel_layout)
 +                frame->channel_layout = avctx->channel_layout;
 +            if (!av_frame_get_channels(frame))
 +                av_frame_set_channels(frame, avctx->channels);
 +            if (!frame->sample_rate)
 +                frame->sample_rate = avctx->sample_rate;
 +        }
  
 +        side= av_packet_get_side_data(avctx->pkt, AV_PKT_DATA_SKIP_SAMPLES, &side_size);
 +        if(side && side_size>=10) {
 +            avctx->internal->skip_samples = AV_RL32(side);
 +            av_log(avctx, AV_LOG_DEBUG, "skip %d samples due to side data\n",
 +                   avctx->internal->skip_samples);
 +            discard_padding = AV_RL32(side + 4);
 +        }
 +        if (avctx->internal->skip_samples && *got_frame_ptr) {
 +            if(frame->nb_samples <= avctx->internal->skip_samples){
 +                *got_frame_ptr = 0;
 +                avctx->internal->skip_samples -= frame->nb_samples;
 +                av_log(avctx, AV_LOG_DEBUG, "skip whole frame, skip left: %d\n",
 +                       avctx->internal->skip_samples);
 +            } else {
 +                av_samples_copy(frame->extended_data, frame->extended_data, 0, avctx->internal->skip_samples,
 +                                frame->nb_samples - avctx->internal->skip_samples, avctx->channels, frame->format);
 +                if(avctx->pkt_timebase.num && avctx->sample_rate) {
 +                    int64_t diff_ts = av_rescale_q(avctx->internal->skip_samples,
 +                                                   (AVRational){1, avctx->sample_rate},
 +                                                   avctx->pkt_timebase);
 +                    if(frame->pkt_pts!=AV_NOPTS_VALUE)
 +                        frame->pkt_pts += diff_ts;
 +                    if(frame->pkt_dts!=AV_NOPTS_VALUE)
 +                        frame->pkt_dts += diff_ts;
 +                    if (av_frame_get_pkt_duration(frame) >= diff_ts)
 +                        av_frame_set_pkt_duration(frame, av_frame_get_pkt_duration(frame) - diff_ts);
 +                } else {
 +                    av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for skipped samples.\n");
 +                }
 +                av_log(avctx, AV_LOG_DEBUG, "skip %d/%d samples\n",
 +                       avctx->internal->skip_samples, frame->nb_samples);
 +                frame->nb_samples -= avctx->internal->skip_samples;
 +                avctx->internal->skip_samples = 0;
 +            }
 +        }
 +
 +        if (discard_padding > 0 && discard_padding <= frame->nb_samples && *got_frame_ptr) {
 +            if (discard_padding == frame->nb_samples) {
 +                *got_frame_ptr = 0;
 +            } else {
 +                if(avctx->pkt_timebase.num && avctx->sample_rate) {
 +                    int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding,
 +                                                   (AVRational){1, avctx->sample_rate},
 +                                                   avctx->pkt_timebase);
 +                    if (av_frame_get_pkt_duration(frame) >= diff_ts)
 +                        av_frame_set_pkt_duration(frame, av_frame_get_pkt_duration(frame) - diff_ts);
 +                } else {
 +                    av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n");
 +                }
 +                av_log(avctx, AV_LOG_DEBUG, "discard %d/%d samples\n",
 +                       discard_padding, frame->nb_samples);
 +                frame->nb_samples -= discard_padding;
 +            }
 +        }
++fail:
 +        avctx->pkt = NULL;
 +        if (did_split) {
 +            av_packet_free_side_data(&tmp);
 +            if(ret == tmp.size)
 +                ret = avpkt->size;
 +        }
 +
 +        if (ret >= 0 && *got_frame_ptr) {
              if (!avctx->refcounted_frames) {
                  avci->to_free = *frame;
                  avci->to_free.extended_data = avci->to_free.data;