Merge commit '37a749012aaacc801fe860428417a6d7b81c103f'
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 9 Dec 2013 17:58:41 +0000 (18:58 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Mon, 9 Dec 2013 18:37:53 +0000 (19:37 +0100)
* commit '37a749012aaacc801fe860428417a6d7b81c103f':
  lavc: rework handling of refcounted_frames=0

Conflicts:
libavcodec/utils.c

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

Simple merge
@@@ -2011,21 -1379,54 +2017,67 @@@ fail
      return AVERROR_INVALIDDATA;
  }
  
 +static int add_metadata_from_side_data(AVCodecContext *avctx, AVFrame *frame)
 +{
 +    int size;
 +    const uint8_t *side_metadata;
 +
 +    AVDictionary **frame_md = avpriv_frame_get_metadatap(frame);
 +
 +    side_metadata = av_packet_get_side_data(avctx->internal->pkt,
 +                                            AV_PKT_DATA_STRINGS_METADATA, &size);
 +    return av_packet_unpack_dictionary(side_metadata, size, frame_md);
 +}
 +
+ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame)
+ {
+     int ret;
+     /* move the original frame to our backup */
+     av_frame_unref(avci->to_free);
+     av_frame_move_ref(avci->to_free, frame);
+     /* now copy everything except the AVBufferRefs back
+      * note that we make a COPY of the side data, so calling av_frame_free() on
+      * the caller's frame will work properly */
+     ret = av_frame_copy_props(frame, avci->to_free);
+     if (ret < 0)
+         return ret;
+     memcpy(frame->data,     avci->to_free->data,     sizeof(frame->data));
+     memcpy(frame->linesize, avci->to_free->linesize, sizeof(frame->linesize));
+     if (avci->to_free->extended_data != avci->to_free->data) {
+         int planes = av_get_channel_layout_nb_channels(avci->to_free->channel_layout);
+         int size   = planes * sizeof(*frame->extended_data);
+         if (!size) {
+             av_frame_unref(frame);
+             return AVERROR_BUG;
+         }
+         frame->extended_data = av_malloc(size);
+         if (!frame->extended_data) {
+             av_frame_unref(frame);
+             return AVERROR(ENOMEM);
+         }
+         memcpy(frame->extended_data, avci->to_free->extended_data,
+                size);
+     } else
+         frame->extended_data = frame->data;
+     frame->format         = avci->to_free->format;
+     frame->width          = avci->to_free->width;
+     frame->height         = avci->to_free->height;
+     frame->channel_layout = avci->to_free->channel_layout;
+     frame->nb_samples     = avci->to_free->nb_samples;
++    av_frame_set_channels(frame, av_frame_get_channels(avci->to_free));
+     return 0;
+ }
  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;
  
      avcodec_get_frame_defaults(picture);
  
-     if (!avctx->refcounted_frames)
-         av_frame_unref(&avci->to_free);
      if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
 +        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->internal->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->internal->pkt = NULL;
 +        if (did_split) {
 +            av_packet_free_side_data(&tmp);
 +            if(ret == tmp.size)
 +                ret = avpkt->size;
 +        }
 +
          if (*got_picture_ptr) {
              if (!avctx->refcounted_frames) {
-                 avci->to_free = *picture;
-                 avci->to_free.extended_data = avci->to_free.data;
-                 memset(picture->buf, 0, sizeof(picture->buf));
+                 int err = unrefcount_frame(avci, picture);
+                 if (err < 0)
+                     return err;
              }
  
              avctx->frame_number++;
@@@ -2186,116 -1506,18 +2235,111 @@@ int attribute_align_arg avcodec_decode_
  
      avcodec_get_frame_defaults(frame);
  
-     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);
 +        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->internal->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->internal->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->internal->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;
-                 memset(frame->buf, 0, sizeof(frame->buf));
-                 frame->extended_buf    = NULL;
-                 frame->nb_extended_buf = 0;
+                 int err = unrefcount_frame(avci, frame);
+                 if (err < 0)
+                     return err;
              }
          } else
              av_frame_unref(frame);
@@@ -2531,10 -1583,7 +2575,9 @@@ av_cold int avcodec_close(AVCodecContex
          if (avctx->codec && avctx->codec->close)
              avctx->codec->close(avctx);
          avctx->coded_frame = NULL;
-         if (!avctx->refcounted_frames)
-             av_frame_unref(&avctx->internal->to_free);
 +        avctx->internal->byte_buffer_size = 0;
 +        av_freep(&avctx->internal->byte_buffer);
+         av_frame_free(&avctx->internal->to_free);
          for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
              av_buffer_pool_uninit(&pool->pools[i]);
          av_freep(&avctx->internal->pool);
@@@ -2852,11 -1859,8 +2895,11 @@@ void avcodec_flush_buffers(AVCodecConte
      else if (avctx->codec->flush)
          avctx->codec->flush(avctx);
  
 +    avctx->pts_correction_last_pts =
 +    avctx->pts_correction_last_dts = INT64_MIN;
 +
      if (!avctx->refcounted_frames)
-         av_frame_unref(&avctx->internal->to_free);
+         av_frame_unref(avctx->internal->to_free);
  }
  
  int av_get_exact_bits_per_sample(enum AVCodecID codec_id)