On Sat, 14 May 2016, Anton Khirnov wrote:

Quoting Martin Storsjö (2016-05-09 13:34:26)
This allows callers with avio write callbacks to get the bytestream
positions that correspond to keyframes, suitable for live streaming.

In the simplest form, a caller could expect that a header is written
to the bytestream during the avformat_write_header, and the data
output to the avio context during e.g. av_write_frame corresponds
exactly to the current packet passed in.

When combined with av_interleaved_write_frame, and with muxers that
do buffering (most muxers that do some sort of fragmenting or
clustering), the mapping from input data to bytestream positions
is nontrivial.

This allows callers to get directly information about what part
of the bytestream is what, without having to resort to assumptions
about the muxer behaviour.

One keyframe/fragment/block can still be split into multiple (if
they are larger than the aviocontext buffer), which would call
the callback with e.g. AVIO_DATA_SYNC_POINT, followed by AVIO_DATA_OPAQUE
for the second time it is called with the following data.

TODO: Do we need a muxer flag to indicate muxers that actually mark
keyframes in this way? All muxers that don't implement anything
special will at least mark header/trailer.

Maybe call it "extended markers"? That said, I'm not sure it would be very
useful. It's probably still all very muxer specific.


TODO: What should the new callback be called? Other suggestions
were write_data_with_type or write_packet2. IMO it shouldn't be called
write_packet2, since it's not supposed to be a complete replacement
used by all callers; it's only supposed to be used by callers that
actually are interested in the data. (If using this callback, the
avio context is flushed potentially more often, which isn't ideal
for all users, e.g. when writing to a file.)

The current name is fine with me.

Hmm, ok


Better suggestions on the data type names are welcome.
---
 doc/APIchanges        |  4 ++++
 libavformat/avio.h    | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/aviobuf.c | 52 +++++++++++++++++++++++++++++++++++++++++--
 libavformat/mux.c     |  6 +++++
 libavformat/version.h |  4 ++--
 5 files changed, 123 insertions(+), 4 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index b83c5ae..c15bc05 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,10 @@ libavutil:     2015-08-28

 API changes, most recent first:

+2016-xx-xx - xxxxxxx - lavf 57.6.0 - avio.h
+  Add AVIODataType, write_data_type, ignore_parse_point and
+  avio_write_marker.
+
 2016-xx-xx - xxxxxxx - lavu 55.10.0 - opt.h
   Add av_opt_copy().

diff --git a/libavformat/avio.h b/libavformat/avio.h
index d60a597..a7c8533 100644
--- a/libavformat/avio.h
+++ b/libavformat/avio.h
@@ -54,6 +54,37 @@ typedef struct AVIOInterruptCB {
 } AVIOInterruptCB;

 /**
+ * Different data types that can be returned via the AVIO
+ * write_data_type callback.
+ */
+enum AVIODataType {

This naming looks a bit too generic to me. Perhaps something like
AVIODataMarkerType would be better?

That sounds fine

+    /**
+     * Header data; this needs to be present for the stream to be decodeable.
+     */
+    AVIO_DATA_HEADER,
+    /**
+     * A point in the output bytestream where a decoder can start decoding
+     * (i.e. a keyframe). A decoder given the data flagged with
+     * AVIO_DATA_HEADER, followed by any AVIO_DATA_SYNC_POINT, should
+     * give decodeable results.
+     */
+    AVIO_DATA_SYNC_POINT,
+    /**
+     * A point in the output bytestream where a demuxer can start parsing
+     * (for non self synchronizing bytestream formats).
+     */
+    AVIO_DATA_PARSE_POINT,

It is not exactly clear what the difference between those two is. And the actual
muxer patch don't make it very obvious either.

What I try to mean is "sync point" == keyframe, "parse point" == any packet boundary, opaque == anything/random/unknown (e.g. if a packet is cut into multiple write callbacks due to a too small IO buffer, or if the muxer doesn't mark anything).

Most users probably only want to know about keyframes, but some users might want to know of all packet/fragment boundaries.

+    /**
+     * This is any, unlabelled data.
+     */
+    AVIO_DATA_OPAQUE,
+    /**
+     * Trailer data. (TODO: Description?)
+     */
+    AVIO_DATA_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
@@ -115,6 +146,24 @@ typedef struct AVIOContext {
      * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not 
seekable.
      */
     int seekable;
+
+    /**
+     * A callback that is used instead of write_packet.
+     */
+    int (*write_data_type)(void *opaque, uint8_t *buf, int buf_size,
+                           enum AVIODataType type, int64_t time);
+    /**
+     * If set, don't call write_data_type separately for AVIO_DATA_PARSE_POINT,
+     * but ignore them and treat them as AVIO_DATA_OPAQUE (to avoid needlessly
+     * small chunks of data returned from the callback).
+     */
+    int ignore_parse_point;
+
+    /**
+     * Internal, not meant to be used from outside of AVIOContext.
+     */
+    enum AVIODataType current_type;
+    int64_t last_time;

I guess we should switch the internal callers to allocate AVIOContext
dynamically and move this stuff to an AVIOInternal. Not saying you have to do it
now, just a not for the future.

That sounds like a decent plan.

// Martin
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to