diff --git a/doc/APIchanges b/doc/APIchanges index 5c7d21a5b7..9ca71b7f8b 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,10 @@ libavutil: 2015-08-28 API changes, most recent first: +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 / 0c4468d - lavu 55.26.100 / 55.12.0 - opt.h Add av_stereo3d_type_name() and av_stereo3d_from_name(). diff --git a/libavformat/avio.h b/libavformat/avio.h index 5e86f7ecc4..b1ce1d1c72 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -96,6 +96,42 @@ 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. @@ -259,6 +295,24 @@ typedef struct AVIOContext { * ',' 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; /** @@ -411,6 +465,18 @@ int avio_put_str16le(AVIOContext *s, const char *str); */ int avio_put_str16be(AVIOContext *s, const char *str); +/** + * Mark the written bytestream as a specific type. + * + * Zero-length ranges are omitted from the output. + * + * @param time the stream time the current bytestream pos corresponds to + * (in AV_TIME_BASE units), or AV_NOPTS_VALUE if unknown or not + * applicable + * @param type the kind of data written starting at the current pos + */ +void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type); + /** * ORing this as the "whence" parameter to a seek function causes it to * return the filesize without seeking anywhere. Supporting this is optional. diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index f02ae21dfd..95793c92cd 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -115,6 +115,11 @@ int ffio_init_context(AVIOContext *s, s->read_pause = NULL; s->read_seek = NULL; + s->write_data_type = NULL; + s->ignore_boundary_point = 0; + s->current_type = AVIO_DATA_MARKER_UNKNOWN; + s->last_time = AV_NOPTS_VALUE; + return 0; } @@ -137,12 +142,24 @@ AVIOContext *avio_alloc_context( 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->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; s->writeout_count ++; s->pos += len; } @@ -450,6 +467,37 @@ void avio_wb24(AVIOContext *s, unsigned int val) 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) diff --git a/libavformat/mux.c b/libavformat/mux.c index 76db60752f..8488043006 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -475,6 +475,8 @@ static int init_pts(AVFormatContext *s) 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) { int ret = s->oformat->write_header(s); if (ret >= 0 && s->pb && s->pb->error < 0) @@ -486,6 +488,8 @@ static int write_header_internal(AVFormatContext *s) 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; } @@ -1164,12 +1168,15 @@ int av_write_trailer(AVFormatContext *s) } 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->deinit) s->oformat->deinit(s); diff --git a/libavformat/version.h b/libavformat/version.h index 0293b488c8..543afbb166 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ // 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, \