Merge commit '8de1ee9f725aa3c550f425bd3120bcd95d5b2ea8'
authorHendrik Leppkes <h.leppkes@gmail.com>
Wed, 11 Nov 2015 13:37:48 +0000 (14:37 +0100)
committerHendrik Leppkes <h.leppkes@gmail.com>
Wed, 11 Nov 2015 13:37:48 +0000 (14:37 +0100)
* commit '8de1ee9f725aa3c550f425bd3120bcd95d5b2ea8':
  lavf: deprecate compute_pkt_fields2

Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>
1  2 
libavformat/avformat.h
libavformat/internal.h
libavformat/mux.c
libavformat/utils.c
libavformat/version.h

@@@ -807,20 -688,8 +807,22 @@@ typedef struct AVIndexEntry 
   */
  #define AV_DISPOSITION_ATTACHED_PIC      0x0400
  
+ typedef struct AVStreamInternal AVStreamInternal;
 +/**
 + * To specify text track kind (different from subtitles default).
 + */
 +#define AV_DISPOSITION_CAPTIONS     0x10000
 +#define AV_DISPOSITION_DESCRIPTIONS 0x20000
 +#define AV_DISPOSITION_METADATA     0x40000
 +
 +/**
 + * Options for behavior on timestamp wrap detection.
 + */
 +#define AV_PTS_WRAP_IGNORE      0   ///< ignore the wrap
 +#define AV_PTS_WRAP_ADD_OFFSET  1   ///< add the format specific offset on wrap detection
 +#define AV_PTS_WRAP_SUB_OFFSET  -1  ///< subtract the format specific offset on wrap detection
 +
  /**
   * Stream structure.
   * New fields can be added to the end with minor version bumps.
@@@ -1036,154 -881,13 +1038,160 @@@ typedef struct AVStream 
      int nb_index_entries;
      unsigned int index_entries_allocated_size;
  
 +    /**
 +     * Real base framerate of the stream.
 +     * This is the lowest framerate with which all timestamps can be
 +     * represented accurately (it is the least common multiple of all
 +     * framerates in the stream). Note, this value is just a guess!
 +     * For example, if the time base is 1/90000 and all frames have either
 +     * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1.
 +     *
 +     * Code outside avformat should access this field using:
 +     * av_stream_get/set_r_frame_rate(stream)
 +     */
 +    AVRational r_frame_rate;
 +
 +    /**
 +     * Stream Identifier
 +     * This is the MPEG-TS stream identifier +1
 +     * 0 means unknown
 +     */
 +    int stream_identifier;
 +
 +    int64_t interleaver_chunk_size;
 +    int64_t interleaver_chunk_duration;
 +
 +    /**
 +     * stream probing state
 +     * -1   -> probing finished
 +     *  0   -> no probing requested
 +     * rest -> perform probing with request_probe being the minimum score to accept.
 +     * NOT PART OF PUBLIC API
 +     */
 +    int request_probe;
 +    /**
 +     * Indicates that everything up to the next keyframe
 +     * should be discarded.
 +     */
 +    int skip_to_keyframe;
 +
 +    /**
 +     * Number of samples to skip at the start of the frame decoded from the next packet.
 +     */
 +    int skip_samples;
 +
 +    /**
 +     * If not 0, the number of samples that should be skipped from the start of
 +     * the stream (the samples are removed from packets with pts==0, which also
 +     * assumes negative timestamps do not happen).
 +     * Intended for use with formats such as mp3 with ad-hoc gapless audio
 +     * support.
 +     */
 +    int64_t start_skip_samples;
 +
 +    /**
 +     * If not 0, the first audio sample that should be discarded from the stream.
 +     * This is broken by design (needs global sample count), but can't be
 +     * avoided for broken by design formats such as mp3 with ad-hoc gapless
 +     * audio support.
 +     */
 +    int64_t first_discard_sample;
 +
 +    /**
 +     * The sample after last sample that is intended to be discarded after
 +     * first_discard_sample. Works on frame boundaries only. Used to prevent
 +     * early EOF if the gapless info is broken (considered concatenated mp3s).
 +     */
 +    int64_t last_discard_sample;
 +
 +    /**
 +     * Number of internally decoded frames, used internally in libavformat, do not access
 +     * its lifetime differs from info which is why it is not in that structure.
 +     */
 +    int nb_decoded_frames;
 +
 +    /**
 +     * Timestamp offset added to timestamps before muxing
 +     * NOT PART OF PUBLIC API
 +     */
 +    int64_t mux_ts_offset;
 +
 +    /**
 +     * Internal data to check for wrapping of the time stamp
 +     */
 +    int64_t pts_wrap_reference;
 +
 +    /**
 +     * Options for behavior, when a wrap is detected.
 +     *
 +     * Defined by AV_PTS_WRAP_ values.
 +     *
 +     * If correction is enabled, there are two possibilities:
 +     * If the first time stamp is near the wrap point, the wrap offset
 +     * will be subtracted, which will create negative time stamps.
 +     * Otherwise the offset will be added.
 +     */
 +    int pts_wrap_behavior;
 +
 +    /**
 +     * Internal data to prevent doing update_initial_durations() twice
 +     */
 +    int update_initial_durations_done;
 +
 +    /**
 +     * Internal data to generate dts from pts
 +     */
 +    int64_t pts_reorder_error[MAX_REORDER_DELAY+1];
 +    uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1];
 +
 +    /**
 +     * Internal data to analyze DTS and detect faulty mpeg streams
 +     */
 +    int64_t last_dts_for_order_check;
 +    uint8_t dts_ordered;
 +    uint8_t dts_misordered;
 +
 +    /**
 +     * Internal data to inject global side data
 +     */
 +    int inject_global_side_data;
 +
 +    /**
 +     * String containing paris of key and values describing recommended encoder configuration.
 +     * Paris are separated by ','.
 +     * Keys are separated from values by '='.
 +     */
 +    char *recommended_encoder_configuration;
 +
 +    /**
 +     * display aspect ratio (0 if unknown)
 +     * - encoding: unused
 +     * - decoding: Set by libavformat to calculate sample_aspect_ratio internally
 +     */
 +    AVRational display_aspect_ratio;
 +
 +    struct FFFrac *priv_pts;
++
+     /**
+      * An opaque field for libavformat internal usage.
+      * Must not be accessed in any way by callers.
+      */
+     AVStreamInternal *internal;
  } AVStream;
  
 +AVRational av_stream_get_r_frame_rate(const AVStream *s);
 +void       av_stream_set_r_frame_rate(AVStream *s, AVRational r);
 +struct AVCodecParserContext *av_stream_get_parser(const AVStream *s);
 +char* av_stream_get_recommended_encoder_configuration(const AVStream *s);
 +void  av_stream_set_recommended_encoder_configuration(AVStream *s, char *configuration);
 +
 +/**
 + * Returns the pts of the last muxed packet + its duration
 + *
 + * the retuned value is undefined when used with a demuxer.
 + */
 +int64_t    av_stream_get_end_pts(const AVStream *st);
 +
  #define AV_PROGRAM_RUNNING 1
  
  /**
@@@ -110,11 -91,21 +110,23 @@@ struct AVFormatInternal 
       */
      AVRational offset_timebase;
  
+ #if FF_API_COMPUTE_PKT_FIELDS2
+     int missing_ts_warning;
+ #endif
++
 +    int inject_global_side_data;
 +
 +    int avoid_negative_ts_use_pts;
  };
  
 -void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem);
 -
+ struct AVStreamInternal {
+     /**
+      * Set to 1 if the codec allows reordering, so pts can be different
+      * from dts.
+      */
+     int reorder;
+ };
  #ifdef __GNUC__
  #define dynarray_add(tab, nb_ptr, elem)\
  do {\
@@@ -239,7 -92,7 +239,8 @@@ static int init_muxer(AVFormatContext *
      AVDictionary *tmp = NULL;
      AVCodecContext *codec = NULL;
      AVOutputFormat *of = s->oformat;
+     const AVCodecDescriptor *desc;
 +    AVDictionaryEntry *e;
  
      if (options)
          av_dict_copy(&tmp, *options, 0);
@@@ -335,14 -172,17 +336,18 @@@ FF_ENABLE_DEPRECATION_WARNING
              break;
          }
  
+         desc = avcodec_descriptor_get(codec->codec_id);
+         if (desc && desc->props & AV_CODEC_PROP_REORDER)
+             st->internal->reorder = 1;
          if (of->codec_tag) {
 -            if (codec->codec_tag &&
 -                codec->codec_id == AV_CODEC_ID_RAWVIDEO &&
 -                !av_codec_get_tag(of->codec_tag, codec->codec_id) &&
 -                !validate_codec_tag(s, st)) {
 +            if (   codec->codec_tag
 +                && codec->codec_id == AV_CODEC_ID_RAWVIDEO
 +                && (   av_codec_get_tag(of->codec_tag, codec->codec_id) == 0
 +                    || av_codec_get_tag(of->codec_tag, codec->codec_id) == MKTAG('r', 'a', 'w', ' '))
 +                && !validate_codec_tag(s, st)) {
                  // the current rawvideo encoding system ends up setting
 -                // the wrong codec_tag for avi, we override it here
 +                // the wrong codec_tag for avi/mov, we override it here
                  codec->codec_tag = 0;
              }
              if (codec->codec_tag) {
@@@ -475,31 -263,28 +480,42 @@@ int avformat_write_header(AVFormatConte
      return 0;
  }
  
 +#define AV_PKT_FLAG_UNCODED_FRAME 0x2000
 +
 +/* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but
 +   it is only being used internally to this file as a consistency check.
 +   The value is chosen to be very unlikely to appear on its own and to cause
 +   immediate failure if used anywhere as a real size. */
 +#define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame))
 +
 +
+ #if FF_API_COMPUTE_PKT_FIELDS2
  //FIXME merge with compute_pkt_fields
  static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
  {
 -    int delay = FFMAX(st->codec->has_b_frames, !!st->codec->max_b_frames);
 +    int delay = FFMAX(st->codec->has_b_frames, st->codec->max_b_frames > 0);
      int num, den, i;
 +    int frame_size;
  
 -    av_log(s, AV_LOG_TRACE, "compute_pkt_fields2: pts:%" PRId64 " dts:%" PRId64 " cur_dts:%" PRId64 " b:%d size:%d st:%d\n",
 -            pkt->pts, pkt->dts, st->cur_dts, delay, pkt->size, pkt->stream_index);
+     if (!s->internal->missing_ts_warning &&
+         !(s->oformat->flags & AVFMT_NOTIMESTAMPS) &&
+         (pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE)) {
+         av_log(s, AV_LOG_WARNING,
+                "Timestamps are unset in a packet for stream %d. "
+                "This is deprecated and will stop working in the future. "
+                "Fix your code to set the timestamps properly\n", st->index);
+         s->internal->missing_ts_warning = 1;
+     }
 +    if (s->debug & FF_FDEBUG_TS)
 +        av_log(s, AV_LOG_TRACE, "compute_pkt_fields2: pts:%s dts:%s cur_dts:%s b:%d size:%d st:%d\n",
 +            av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), delay, pkt->size, pkt->stream_index);
  
 -/*    if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
 - *      return AVERROR(EINVAL);*/
 +    if (pkt->duration < 0 && st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) {
 +        av_log(s, AV_LOG_WARNING, "Packet with invalid duration %"PRId64" in stream %d\n",
 +               pkt->duration, pkt->stream_index);
 +        pkt->duration = 0;
 +    }
  
      /* duration field */
      if (pkt->duration == 0) {
          return AVERROR(EINVAL);
      }
  
 -    av_log(s, AV_LOG_TRACE, "av_write_frame: pts2:%"PRId64" dts2:%"PRId64"\n",
 -            pkt->pts, pkt->dts);
 -    st->cur_dts = pkt->dts;
 +    if (s->debug & FF_FDEBUG_TS)
 +        av_log(s, AV_LOG_TRACE, "av_write_frame: pts2:%s dts2:%s\n",
 +            av_ts2str(pkt->pts), av_ts2str(pkt->dts));
  
 +    st->cur_dts = pkt->dts;
 +    st->priv_pts->val = pkt->dts;
 +
 +    /* update pts */
 +    switch (st->codec->codec_type) {
 +    case AVMEDIA_TYPE_AUDIO:
 +        frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ?
 +                     ((AVFrame *)pkt->data)->nb_samples :
 +                     av_get_audio_frame_duration(st->codec, pkt->size);
 +
 +        /* HACK/FIXME, we skip the initial 0 size packets as they are most
 +         * likely equal to the encoder delay, but it would be better if we
 +         * had the real timestamps from the encoder */
 +        if (frame_size >= 0 && (pkt->size || st->priv_pts->num != st->priv_pts->den >> 1 || st->priv_pts->val)) {
 +            frac_add(st->priv_pts, (int64_t)st->time_base.den * frame_size);
 +        }
 +        break;
 +    case AVMEDIA_TYPE_VIDEO:
 +        frac_add(st->priv_pts, (int64_t)st->time_base.den * st->codec->time_base.num);
 +        break;
 +    }
      return 0;
  }
+ #endif
  
 -/*
 +/**
 + * Make timestamps non negative, move side data from payload to internal struct, call muxer, and restore
 + * sidedata.
 + *
   * FIXME: this function should NEVER get undefined pts/dts beside when the
   * AVFMT_NOTIMESTAMPS is set.
   * Those additional safety checks should be dropped once the correct checks
@@@ -701,15 -406,61 +718,67 @@@ static int prepare_input_packet(AVForma
      if (ret < 0)
          return ret;
  
+ #if !FF_API_COMPUTE_PKT_FIELDS2
+     /* sanitize the timestamps */
+     if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
+         AVStream *st = s->streams[pkt->stream_index];
+         /* when there is no reordering (so dts is equal to pts), but
+          * only one of them is set, set the other as well */
+         if (!st->internal->reorder) {
+             if (pkt->pts == AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE)
+                 pkt->pts = pkt->dts;
+             if (pkt->dts == AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE)
+                 pkt->dts = pkt->pts;
+         }
+         /* check that the timestamps are set */
+         if (pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE) {
+             av_log(s, AV_LOG_ERROR,
+                    "Timestamps are unset in a packet for stream %d\n", st->index);
+             return AVERROR(EINVAL);
+         }
+         /* check that the dts are increasing (or at least non-decreasing,
+          * if the format allows it */
+         if (st->cur_dts != AV_NOPTS_VALUE &&
+             ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) && st->cur_dts >= pkt->dts) ||
+              st->cur_dts > pkt->dts)) {
+             av_log(s, AV_LOG_ERROR,
+                    "Application provided invalid, non monotonically increasing "
+                    "dts to muxer in stream %d: %" PRId64 " >= %" PRId64 "\n",
+                    st->index, st->cur_dts, pkt->dts);
+             return AVERROR(EINVAL);
+         }
+         if (pkt->pts < pkt->dts) {
+             av_log(s, AV_LOG_ERROR, "pts %" PRId64 " < dts %" PRId64 " in stream %d\n",
+                    pkt->pts, pkt->dts, st->index);
+             return AVERROR(EINVAL);
+         }
+     }
+ #endif
+     return 0;
+ }
+ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
+ {
+     int ret;
+     ret = prepare_input_packet(s, pkt);
+     if (ret < 0)
+         return ret;
      if (!pkt) {
 -        if (s->oformat->flags & AVFMT_ALLOW_FLUSH)
 -            return s->oformat->write_packet(s, pkt);
 +        if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
 +            ret = s->oformat->write_packet(s, NULL);
 +            if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
 +                avio_flush(s->pb);
 +            if (ret >= 0 && s->pb && s->pb->error < 0)
 +                ret = s->pb->error;
 +            return ret;
 +        }
          return 1;
      }
  
  
      if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
          return ret;
+ #endif
  
      ret = write_packet(s, pkt);
 +    if (ret >= 0 && s->pb && s->pb->error < 0)
 +        ret = s->pb->error;
  
      if (ret >= 0)
          s->streams[pkt->stream_index]->nb_frames++;
@@@ -937,12 -630,12 +1008,14 @@@ int av_interleaved_write_frame(AVFormat
      if (pkt) {
          AVStream *st = s->streams[pkt->stream_index];
  
 -        av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame size:%d dts:%" PRId64 " pts:%" PRId64 "\n",
 -                pkt->size, pkt->dts, pkt->pts);
 +        if (s->debug & FF_FDEBUG_TS)
 +            av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame size:%d dts:%s pts:%s\n",
 +                pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts));
 +
+ #if FF_API_COMPUTE_PKT_FIELDS2
          if ((ret = compute_pkt_fields2(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
              goto fail;
+ #endif
  
          if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
              ret = AVERROR(EINVAL);
@@@ -3669,18 -2460,16 +3669,20 @@@ static void free_stream(AVStream **pst
      if (st->attached_pic.data)
          av_packet_unref(&st->attached_pic);
  
+     av_freep(&st->internal);
      av_dict_free(&st->metadata);
      av_freep(&st->probe_data.buf);
 -    av_free(st->index_entries);
 -    av_free(st->codec->extradata);
 -    av_free(st->codec->subtitle_header);
 -    av_free(st->codec);
 -    av_free(st->priv_data);
 -    av_free(st->info);
 +    av_freep(&st->index_entries);
 +    av_freep(&st->codec->extradata);
 +    av_freep(&st->codec->subtitle_header);
 +    av_freep(&st->codec);
 +    av_freep(&st->priv_data);
 +    if (st->info)
 +        av_freep(&st->info->duration_error);
 +    av_freep(&st->info);
 +    av_freep(&st->recommended_encoder_configuration);
 +    av_freep(&st->priv_pts);
  
      av_freep(pst);
  }
@@@ -3821,10 -2588,11 +3828,13 @@@ AVStream *avformat_new_stream(AVFormatC
      st->info->fps_first_dts = AV_NOPTS_VALUE;
      st->info->fps_last_dts  = AV_NOPTS_VALUE;
  
 +    st->inject_global_side_data = s->internal->inject_global_side_data;
 +
      s->streams[s->nb_streams++] = st;
      return st;
+ fail:
+     free_stream(&st);
+     return NULL;
  }
  
  AVProgram *av_new_program(AVFormatContext *ac, int id)
  #ifndef FF_API_LAVF_FMT_RAWPICTURE
  #define FF_API_LAVF_FMT_RAWPICTURE      (LIBAVFORMAT_VERSION_MAJOR < 58)
  #endif
+ #ifndef FF_API_COMPUTE_PKT_FIELDS2
+ #define FF_API_COMPUTE_PKT_FIELDS2      (LIBAVFORMAT_VERSION_MAJOR < 58)
+ #endif
  
 +#ifndef FF_API_R_FRAME_RATE
 +#define FF_API_R_FRAME_RATE            1
 +#endif
  #endif /* AVFORMAT_VERSION_H */