On Fri, 27 Jan 2017, Peter Große wrote:
The dash_write function drops data, if no IOContext is initialized.
This might happen when a subordinate muxer calls avio_flush().
Using a dynamic buffer fixes that.
Signed-off-by: Peter Große <[email protected]>
---
libavformat/dashenc.c | 87 +++++++++++++++++++++++++++++----------------------
1 file changed, 50 insertions(+), 37 deletions(-)
This patch at least needs a mention of what muxer would do that.
Currently, the only subordinate muxer you can use is the mp4 one, and that
one (with the configured options) doesn't flush except when told to.
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index a0c7811..86b454e 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -68,11 +68,10 @@ typedef struct AdaptationSet {
typedef struct OutputStream {
AVFormatContext *ctx;
int ctx_inited, as_idx;
- uint8_t iobuf[32768];
AVIOContext *out;
int duration_written;
char initfile[1024];
- int64_t init_start_pos;
+ int64_t init_start_pos, pos;
int init_range_length;
int nb_segments, segments_size, segment_index;
Segment **segments;
@@ -108,14 +107,6 @@ typedef struct DASHContext {
const char *utc_timing_url;
} DASHContext;
-static int dash_write(void *opaque, uint8_t *buf, int buf_size)
-{
- OutputStream *os = opaque;
- if (os->out)
- avio_write(os->out, buf, buf_size);
- return buf_size;
-}
-
// RFC 6381
static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
char *str, int size)
@@ -182,6 +173,29 @@ static void set_codec_str(AVFormatContext *s,
AVCodecParameters *par,
}
}
+static int flush_dynbuf(OutputStream *os, int *range_length)
+{
+ uint8_t *buffer;
+ int ret;
+
+ if (!os->ctx->pb) {
+ return AVERROR(EINVAL);
+ }
+
+ // flush
+ av_write_frame(os->ctx, NULL);
+ avio_flush(os->ctx->pb);
+
+ // write out to file
+ *range_length = avio_close_dyn_buf(os->ctx->pb, &buffer);
+ avio_write(os->out, buffer, *range_length);
+ av_free(buffer);
+
+ // re-open buffer
+ ret = avio_open_dyn_buf(&os->ctx->pb);
+ return ret;
The intermediate variable feels a little superfluous here
+}
+
static void dash_free(AVFormatContext *s)
{
DASHContext *c = s->priv_data;
@@ -203,7 +217,7 @@ static void dash_free(AVFormatContext *s)
if (os->ctx && os->ctx_inited)
av_write_trailer(os->ctx);
if (os->ctx && os->ctx->pb)
- av_free(os->ctx->pb);
+ ffio_free_dyn_buf(&os->ctx->pb);
ff_format_io_close(s, &os->out);
if (os->ctx)
avformat_free_context(os->ctx);
@@ -689,7 +703,7 @@ static int dict_copy_entry(AVDictionary **dst, const
AVDictionary *src, const ch
static int dash_write_header(AVFormatContext *s)
{
DASHContext *c = s->priv_data;
- int ret = 0, i;
+ int ret = 0, i, range_length;
AVOutputFormat *oformat;
char *ptr;
char basename[1024];
@@ -786,11 +800,9 @@ static int dash_write_header(AVFormatContext *s)
st->time_base = s->streams[i]->time_base;
ctx->avoid_negative_ts = s->avoid_negative_ts;
- ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf),
AVIO_FLAG_WRITE, os, NULL, dash_write, NULL);
- if (!ctx->pb) {
- ret = AVERROR(ENOMEM);
+ if ((ret = avio_open_dyn_buf(&ctx->pb)) < 0)
goto fail;
- }
+ ctx->pb->seekable = 0;
if (c->single_file) {
if (c->single_file_name)
@@ -807,11 +819,17 @@ static int dash_write_header(AVFormatContext *s)
os->init_start_pos = 0;
av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
- if ((ret = avformat_write_header(ctx, &opts)) < 0) {
- goto fail;
- }
+ if ((ret = avformat_write_header(ctx, &opts)) < 0)
+ goto fail;
+
+ if ((ret = flush_dynbuf(os, &range_length)) < 0)
+ goto fail;
+
+ if (!c->single_file)
+ ff_format_io_close(s, &os->out);
+
+ os->pos = os->init_range_length = range_length;
This isn't correct. See c5e7ea13d2d4da0c5da91973a547afff6fe9e011. We
intentionally defer writing the init segment until we have passed the
first segment of packets into the muxer, to handle the cases where the
init segments depend on knowledge from the actual first few packets.
(Proper edit lists for handling b-frame delay needs to know the timestamp
of the first packet, and for AC3, the moov box takes a copy of the full
first packet.)
For using the webm muxer, you probably might need to have this behaviour
conditional on the kind of muxer.
os->ctx_inited = 1;
- avio_flush(ctx->pb);
av_dict_free(&opts);
av_log(s, AV_LOG_VERBOSE, "Representation %d init segment will be written
to: %s\n", i, filename);
@@ -946,7 +964,6 @@ static int dash_flush(AVFormatContext *s, int final, int
stream)
for (i = 0; i < s->nb_streams; i++) {
OutputStream *os = &c->streams[i];
char filename[1024] = "", full_path[1024], temp_path[1024];
- int64_t start_pos;
int range_length, index_length = 0;
if (!os->duration_written)
@@ -964,15 +981,6 @@ static int dash_flush(AVFormatContext *s, int final, int
stream)
continue;
}
- if (!os->init_range_length) {
- av_write_frame(os->ctx, NULL);
- os->init_range_length = avio_tell(os->ctx->pb);
- if (!c->single_file)
- ff_format_io_close(s, &os->out);
- }
-
- start_pos = avio_tell(os->ctx->pb);
-
if (!c->single_file) {
dash_fill_tmpl_params(filename, sizeof(filename), c->media_seg_name, i,
os->segment_index, os->bit_rate, os->start_pts);
snprintf(full_path, sizeof(full_path), "%s%s", c->dirname,
filename);
@@ -980,18 +988,16 @@ static int dash_flush(AVFormatContext *s, int final, int
stream)
ret = s->io_open(s, &os->out, temp_path, AVIO_FLAG_WRITE, NULL);
if (ret < 0)
break;
- write_styp(os->ctx->pb);
} else {
snprintf(full_path, sizeof(full_path), "%s%s", c->dirname,
os->initfile);
}
- av_write_frame(os->ctx, NULL);
- avio_flush(os->ctx->pb);
- os->duration_written = 0;
+ ret = flush_dynbuf(os, &range_length);
+ if (ret < 0)
+ break;
- range_length = avio_tell(os->ctx->pb) - start_pos;
if (c->single_file) {
- find_index_range(s, full_path, start_pos, &index_length);
+ find_index_range(s, full_path, os->pos, &index_length);
} else {
ff_format_io_close(s, &os->out);
ret = ff_rename(temp_path, full_path);
@@ -1009,8 +1015,15 @@ static int dash_flush(AVFormatContext *s, int final, int
stream)
}
}
- add_segment(os, filename, os->start_pts, os->max_pts - os->start_pts,
start_pos, range_length, index_length);
+ add_segment(os, filename, os->start_pts, os->max_pts - os->start_pts,
os->pos, range_length, index_length);
av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to:
%s\n", i, os->segment_index, full_path);
+
+ // set new position
+ os->duration_written = 0;
+ os->pos += range_length;
+
+ // write chunk header
+ write_styp(os->ctx->pb);
Doesn't this miss writing the styp header for the first segment?
// Martin
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel