Merge commit 'db7968bff4851c2be79b15b2cb2ae747424d2fca'
authorMatthieu Bouron <matthieu.bouron@stupeflix.com>
Thu, 23 Jun 2016 13:27:00 +0000 (15:27 +0200)
committerMatthieu Bouron <matthieu.bouron@stupeflix.com>
Thu, 23 Jun 2016 13:59:44 +0000 (15:59 +0200)
* commit 'db7968bff4851c2be79b15b2cb2ae747424d2fca':
  avio: Allow custom IO users to get labels for the output bytestream

Merged-by: Matthieu Bouron <matthieu.bouron@stupeflix.com>
1  2 
doc/APIchanges
libavformat/avio.h
libavformat/aviobuf.c
libavformat/mux.c
libavformat/version.h

diff --cc doc/APIchanges
@@@ -15,17 -13,20 +15,21 @@@ libavutil:     2015-08-2
  
  API changes, most recent first:
  
 -2016-xx-xx - xxxxxxx - lavf 57.7.0 - avio.h
++2016-xx-xx - xxxxxxx / db7968b - lavf 57.40.100 / 57.7.0 - avio.h
+   Add AVIODataMarkerType, write_data_type, ignore_boundary_point and
+   avio_write_marker.
 -2016-xx-xx - xxxxxxx - lavu 55.12.0 - opt.h
 +2016-xx-xx - xxxxxxx / 0c4468d - lavu 55.26.100 / 55.12.0 - opt.h
    Add av_stereo3d_type_name() and av_stereo3d_from_name().
  
 -2016-xx-xx - xxxxxxx - lavu 55.11.0 - hwcontext_dxva2.h
 +2016-06-22 - xxxxxxx - lavu 55.25.100 - hwcontext_dxva2.h
    Add new installed header with DXVA2-specific hwcontext definitions.
  
 -2016-xx-xx - xxxxxxx - lavu 55.10.0 - opt.h
 -  Add av_opt_copy().
 +2016-04-27 - fb91871 - lavu 55.23.100 - log.h
 +  Add a new function av_log_format_line2() which returns number of bytes
 +  written to the target buffer.
  
 -2016-xx-xx - xxxxxxx - lavc 57.16.0 - avcodec.h
 +2016-04-21 - 7fc329e - lavc 57.37.100 - avcodec.h
    Add a new audio/video encoding and decoding API with decoupled input
    and output -- avcodec_send_packet(), avcodec_receive_frame(),
    avcodec_send_frame() and avcodec_receive_packet().
@@@ -53,50 -54,42 +53,86 @@@ typedef struct AVIOInterruptCB 
  } AVIOInterruptCB;
  
  /**
 + * Directory entry types.
 + */
 +enum AVIODirEntryType {
 +    AVIO_ENTRY_UNKNOWN,
 +    AVIO_ENTRY_BLOCK_DEVICE,
 +    AVIO_ENTRY_CHARACTER_DEVICE,
 +    AVIO_ENTRY_DIRECTORY,
 +    AVIO_ENTRY_NAMED_PIPE,
 +    AVIO_ENTRY_SYMBOLIC_LINK,
 +    AVIO_ENTRY_SOCKET,
 +    AVIO_ENTRY_FILE,
 +    AVIO_ENTRY_SERVER,
 +    AVIO_ENTRY_SHARE,
 +    AVIO_ENTRY_WORKGROUP,
 +};
 +
 +/**
 + * Describes single entry of the directory.
 + *
 + * Only name and type fields are guaranteed be set.
 + * Rest of fields are protocol or/and platform dependent and might be unknown.
 + */
 +typedef struct AVIODirEntry {
 +    char *name;                           /**< Filename */
 +    int type;                             /**< Type of the entry */
 +    int utf8;                             /**< Set to 1 when name is encoded with UTF-8, 0 otherwise.
 +                                               Name can be encoded with UTF-8 even though 0 is set. */
 +    int64_t size;                         /**< File size in bytes, -1 if unknown. */
 +    int64_t modification_timestamp;       /**< Time of last modification in microseconds since unix
 +                                               epoch, -1 if unknown. */
 +    int64_t access_timestamp;             /**< Time of last access in microseconds since unix epoch,
 +                                               -1 if unknown. */
 +    int64_t status_change_timestamp;      /**< Time of last status change in microseconds since unix
 +                                               epoch, -1 if unknown. */
 +    int64_t user_id;                      /**< User ID of owner, -1 if unknown. */
 +    int64_t group_id;                     /**< Group ID of owner, -1 if unknown. */
 +    int64_t filemode;                     /**< Unix file mode, -1 if unknown. */
 +} AVIODirEntry;
 +
 +typedef struct AVIODirContext {
 +    struct URLContext *url_context;
 +} AVIODirContext;
 +
 +/**
+  * Different data types that can be returned via the AVIO
+  * write_data_type callback.
+  */
+ enum AVIODataMarkerType {
+     /**
+      * Header data; this needs to be present for the stream to be decodeable.
+      */
+     AVIO_DATA_MARKER_HEADER,
+     /**
+      * A point in the output bytestream where a decoder can start decoding
+      * (i.e. a keyframe). A demuxer/decoder given the data flagged with
+      * AVIO_DATA_MARKER_HEADER, followed by any AVIO_DATA_MARKER_SYNC_POINT,
+      * should give decodeable results.
+      */
+     AVIO_DATA_MARKER_SYNC_POINT,
+     /**
+      * A point in the output bytestream where a demuxer can start parsing
+      * (for non self synchronizing bytestream formats). That is, any
+      * non-keyframe packet start point.
+      */
+     AVIO_DATA_MARKER_BOUNDARY_POINT,
+     /**
+      * This is any, unlabelled data. It can either be a muxer not marking
+      * any positions at all, it can be an actual boundary/sync point
+      * that the muxer chooses not to mark, or a later part of a packet/fragment
+      * that is cut into multiple write callbacks due to limited IO buffer size.
+      */
+     AVIO_DATA_MARKER_UNKNOWN,
+     /**
+      * Trailer data, which doesn't contain actual content, but only for
+      * finalizing the output file.
+      */
+     AVIO_DATA_MARKER_TRAILER
+ };
+ /**
   * Bytestream IO Context.
   * New fields can be added to the end with minor version bumps.
   * Removal, reordering and changes to existing fields require a major
@@@ -207,58 -153,22 +243,76 @@@ typedef struct AVIOContext 
      int seekable;
  
      /**
 +     * max filesize, used to limit allocations
 +     * This field is internal to libavformat and access from outside is not allowed.
 +     */
 +    int64_t maxsize;
 +
 +    /**
 +     * avio_read and avio_write should if possible be satisfied directly
 +     * instead of going through a buffer, and avio_seek will always
 +     * call the underlying seek function directly.
 +     */
 +    int direct;
 +
 +    /**
 +     * Bytes read statistic
 +     * This field is internal to libavformat and access from outside is not allowed.
 +     */
 +    int64_t bytes_read;
 +
 +    /**
 +     * seek statistic
 +     * This field is internal to libavformat and access from outside is not allowed.
 +     */
 +    int seek_count;
 +
 +    /**
 +     * writeout statistic
 +     * This field is internal to libavformat and access from outside is not allowed.
 +     */
 +    int writeout_count;
 +
 +    /**
 +     * Original buffer size
 +     * used internally after probing and ensure seekback to reset the buffer size
 +     * This field is internal to libavformat and access from outside is not allowed.
 +     */
 +    int orig_buffer_size;
 +
 +    /**
 +     * Threshold to favor readahead over seek.
 +     * This is current internal only, do not use from outside.
 +     */
 +    int short_seek_threshold;
 +
 +    /**
 +     * ',' separated list of allowed protocols.
 +     */
 +    const char *protocol_whitelist;
 +
 +    /**
 +     * ',' separated list of disallowed protocols.
 +     */
 +    const char *protocol_blacklist;
++
++    /**
+      * A callback that is used instead of write_packet.
+      */
+     int (*write_data_type)(void *opaque, uint8_t *buf, int buf_size,
+                            enum AVIODataMarkerType type, int64_t time);
+     /**
+      * If set, don't call write_data_type separately for AVIO_DATA_MARKER_BOUNDARY_POINT,
+      * but ignore them and treat them as AVIO_DATA_MARKER_UNKNOWN (to avoid needlessly
+      * small chunks of data returned from the callback).
+      */
+     int ignore_boundary_point;
+     /**
+      * Internal, not meant to be used from outside of AVIOContext.
+      */
+     enum AVIODataMarkerType current_type;
+     int64_t last_time;
  } AVIOContext;
  
  /**
@@@ -135,22 -165,28 +140,34 @@@ AVIOContext *avio_alloc_context
      return s;
  }
  
 -static void flush_buffer(AVIOContext *s)
 +static void writeout(AVIOContext *s, const uint8_t *data, int len)
  {
-     if (s->write_packet && !s->error) {
-         int ret = s->write_packet(s->opaque, (uint8_t *)data, len);
 -    if (s->buf_ptr > s->buffer) {
 -        if (!s->error) {
 -            int ret = 0;
 -            if (s->write_data_type)
 -                ret = s->write_data_type(s->opaque, s->buffer,
 -                                         s->buf_ptr - s->buffer,
 -                                         s->current_type,
 -                                         s->last_time);
 -            else if (s->write_packet)
 -                ret = s->write_packet(s->opaque, s->buffer,
 -                                      s->buf_ptr - s->buffer);
 -            if (ret < 0) {
 -                s->error = ret;
 -            }
++    if (!s->error) {
++        int ret = 0;
++        if (s->write_data_type)
++            ret = s->write_data_type(s->opaque, (uint8_t *)data,
++                                     len,
++                                     s->current_type,
++                                     s->last_time);
++        else if (s->write_packet)
++            ret = s->write_packet(s->opaque, (uint8_t *)data, len);
 +        if (ret < 0) {
 +            s->error = ret;
          }
 -        if (s->current_type == AVIO_DATA_MARKER_SYNC_POINT ||
 -            s->current_type == AVIO_DATA_MARKER_BOUNDARY_POINT) {
 -            s->current_type = AVIO_DATA_MARKER_UNKNOWN;
 -        }
 -        s->last_time = AV_NOPTS_VALUE;
 +    }
++    if (s->current_type == AVIO_DATA_MARKER_SYNC_POINT ||
++        s->current_type == AVIO_DATA_MARKER_BOUNDARY_POINT) {
++        s->current_type = AVIO_DATA_MARKER_UNKNOWN;
++    }
++    s->last_time = AV_NOPTS_VALUE;
 +    s->writeout_count ++;
 +    s->pos += len;
 +}
 +
 +static void flush_buffer(AVIOContext *s)
 +{
 +    if (s->write_flag && s->buf_ptr > s->buffer) {
 +        writeout(s, s->buffer, s->buf_ptr - s->buffer);
          if (s->update_checksum) {
              s->checksum     = s->update_checksum(s->checksum, s->checksum_ptr,
                                                   s->buf_ptr - s->checksum_ptr);
@@@ -446,10 -415,41 +463,41 @@@ void avio_wl24(AVIOContext *s, unsigne
  
  void avio_wb24(AVIOContext *s, unsigned int val)
  {
 -    avio_wb16(s, val >> 8);
 -    avio_w8(s, val);
 +    avio_wb16(s, (int)val >> 8);
 +    avio_w8(s, (uint8_t)val);
  }
  
+ void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type)
+ {
+     if (!s->write_data_type)
+         return;
+     // If ignoring boundary points, just treat it as unknown
+     if (type == AVIO_DATA_MARKER_BOUNDARY_POINT && s->ignore_boundary_point)
+         type = AVIO_DATA_MARKER_UNKNOWN;
+     // Avoid unnecessary flushes if we are already in non-header/trailer
+     // data and setting the type to unknown
+     if (type == AVIO_DATA_MARKER_UNKNOWN &&
+         (s->current_type != AVIO_DATA_MARKER_HEADER &&
+          s->current_type != AVIO_DATA_MARKER_TRAILER))
+         return;
+     switch (type) {
+     case AVIO_DATA_MARKER_HEADER:
+     case AVIO_DATA_MARKER_TRAILER:
+         // For header/trailer, ignore a new marker of the same type;
+         // consecutive header/trailer markers can be merged.
+         if (type == s->current_type)
+             return;
+         break;
+     }
+     // If we've reached here, we have a new, noteworthy marker.
+     // Flush the previous data and mark the start of the new data.
+     avio_flush(s);
+     s->current_type = type;
+     s->last_time = time;
+ }
  /* Input stream */
  
  static void fill_buffer(AVIOContext *s)
@@@ -436,77 -249,24 +436,81 @@@ fail
      return ret;
  }
  
 -int avformat_write_header(AVFormatContext *s, AVDictionary **options)
 +static int init_pts(AVFormatContext *s)
  {
 -    int ret = 0;
 +    int i;
 +    AVStream *st;
  
 -    if (ret = init_muxer(s, options))
 -        return ret;
 +    /* init PTS generation */
 +    for (i = 0; i < s->nb_streams; i++) {
 +        int64_t den = AV_NOPTS_VALUE;
 +        st = s->streams[i];
 +
 +        switch (st->codecpar->codec_type) {
 +        case AVMEDIA_TYPE_AUDIO:
 +            den = (int64_t)st->time_base.num * st->codecpar->sample_rate;
 +            break;
 +        case AVMEDIA_TYPE_VIDEO:
 +            den = (int64_t)st->time_base.num * st->time_base.den;
 +            break;
 +        default:
 +            break;
 +        }
 +
 +        if (!st->priv_pts)
 +            st->priv_pts = av_mallocz(sizeof(*st->priv_pts));
 +        if (!st->priv_pts)
 +            return AVERROR(ENOMEM);
 +
 +        if (den != AV_NOPTS_VALUE) {
 +            if (den <= 0)
 +                return AVERROR_INVALIDDATA;
  
 +            frac_init(st->priv_pts, 0, 0, den);
 +        }
 +    }
 +
 +    return 0;
 +}
 +
 +static int write_header_internal(AVFormatContext *s)
 +{
+     if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
+         avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
      if (s->oformat->write_header) {
 -        ret = s->oformat->write_header(s);
 +        int ret = s->oformat->write_header(s);
 +        if (ret >= 0 && s->pb && s->pb->error < 0)
 +            ret = s->pb->error;
 +        s->internal->write_header_ret = ret;
          if (ret < 0)
              return ret;
 +        if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
 +            avio_flush(s->pb);
      }
 +    s->internal->header_written = 1;
+     if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
+         avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_UNKNOWN);
 +    return 0;
 +}
 +
 +int avformat_write_header(AVFormatContext *s, AVDictionary **options)
 +{
 +    int ret = 0;
 +
 +    if ((ret = init_muxer(s, options)) < 0)
 +        return ret;
 +
 +    if (!s->oformat->check_bitstream) {
 +        ret = write_header_internal(s);
 +        if (ret < 0)
 +            goto fail;
 +    }
  
 -    if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO) {
 +    if ((ret = init_pts(s)) < 0)
 +        goto fail;
 +
 +    if (s->avoid_negative_ts < 0) {
 +        av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO);
          if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
              s->avoid_negative_ts = 0;
          } else
@@@ -1153,31 -706,17 +1157,34 @@@ int av_write_trailer(AVFormatContext *s
  
          if (ret < 0)
              goto fail;
 +        if(s->pb && s->pb->error)
 +            goto fail;
      }
  
 -    if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
 -        avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
 -    if (s->oformat->write_trailer)
 +    if (!s->internal->header_written) {
 +        ret = s->internal->write_header_ret ? s->internal->write_header_ret : write_header_internal(s);
 +        if (ret < 0)
 +            goto fail;
 +    }
 +
 +fail:
-     if (s->internal->header_written && s->oformat->write_trailer)
++    if (s->internal->header_written && s->oformat->write_trailer) {
++        if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
++            avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
 +        if (ret >= 0) {
          ret = s->oformat->write_trailer(s);
 +        } else {
 +            s->oformat->write_trailer(s);
 +        }
++    }
  
 -    if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
 -        avio_flush(s->pb);
 +    if (s->oformat->deinit)
 +        s->oformat->deinit(s);
  
 -fail:
 +    if (s->pb)
 +       avio_flush(s->pb);
 +    if (ret == 0)
 +       ret = s->pb ? s->pb->error : 0;
      for (i = 0; i < s->nb_streams; i++) {
          av_freep(&s->streams[i]->priv_data);
          av_freep(&s->streams[i]->index_entries);
  
  #include "libavutil/version.h"
  
 -#define LIBAVFORMAT_VERSION_MAJOR 57
 -#define LIBAVFORMAT_VERSION_MINOR  7
 -#define LIBAVFORMAT_VERSION_MICRO  0
 +// Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
 +// Also please add any ticket numbers that you belive might be affected here
 +#define LIBAVFORMAT_VERSION_MAJOR  57
- #define LIBAVFORMAT_VERSION_MINOR  39
++#define LIBAVFORMAT_VERSION_MINOR  40
 +#define LIBAVFORMAT_VERSION_MICRO 100
  
  #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                 LIBAVFORMAT_VERSION_MINOR, \