From patchwork Sat Jan 21 14:39:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Peter_Gro=C3=9Fe?= X-Patchwork-Id: 2271 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp528971vsb; Sat, 21 Jan 2017 06:39:44 -0800 (PST) X-Received: by 10.28.41.135 with SMTP id p129mr7932360wmp.59.1485009583958; Sat, 21 Jan 2017 06:39:43 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id u22si11839046wru.73.2017.01.21.06.39.43; Sat, 21 Jan 2017 06:39:43 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3DBCE68A378; Sat, 21 Jan 2017 16:39:19 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from james.theweblords.de (james.theweblords.de [217.11.55.87]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id DDCC06800CB for ; Sat, 21 Jan 2017 16:39:11 +0200 (EET) Received: (qmail 28076 invoked by uid 210); 21 Jan 2017 14:39:23 -0000 X-Qmail-Scanner-Diagnostics: from x5d808bdc.dyn.telefonica.de (petronios@theweblords.de@x5d808bdc.dyn.telefonica.de) by james (envelope-from , uid 201) with qmail-scanner-2.10st (mhr: 1.0. spamassassin: 3.4.1. perlscan: 2.10st. Clear:RC:1(93.128.139.220):. Processed in 0.044332 secs); 21 Jan 2017 14:39:23 -0000 Received: from x5d808bdc.dyn.telefonica.de (HELO montepegro.fem.tu-ilmenau.de) (petronios@theweblords.de@93.128.139.220) by james.theweblords.de with ESMTPA; 21 Jan 2017 14:39:23 -0000 From: =?UTF-8?q?Peter=20Gro=C3=9Fe?= To: ffmpeg-devel@ffmpeg.org Date: Sat, 21 Jan 2017 15:39:02 +0100 Message-Id: <20170121143909.29028-2-pegro@friiks.de> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170121143909.29028-1-pegro@friiks.de> References: <20170121143909.29028-1-pegro@friiks.de> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/8] libavformat/dashenc: use avio_dynbuf instead of packet_write callback X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: ischluff@mailbox.org, pegro@friiks.de Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 --- libavformat/dashenc.c | 86 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 534fa75..d0a2ab5 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -62,11 +62,10 @@ typedef struct Segment { typedef struct OutputStream { AVFormatContext *ctx; int ctx_inited; - uint8_t iobuf[32768]; AVIOContext *out; int packets_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; @@ -100,14 +99,6 @@ typedef struct DASHContext { int ambiguous_frame_rate; } 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) @@ -174,6 +165,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 everything + av_write_frame(os->ctx, NULL); + avio_flush(os->ctx->pb); + + // write to output + *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; +} + static void dash_free(AVFormatContext *s) { DASHContext *c = s->priv_data; @@ -185,7 +199,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); @@ -624,9 +638,10 @@ static int dash_init(AVFormatContext *s) ctx->avoid_negative_ts = s->avoid_negative_ts; ctx->flags = s->flags; - ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf), AVIO_FLAG_WRITE, os, NULL, dash_write, NULL); - if (!ctx->pb) - return AVERROR(ENOMEM); + ret = avio_open_dyn_buf(&ctx->pb); + if (ret < 0) + return ret; + ctx->pb->seekable = 0; if (c->single_file) { if (c->single_file_name) @@ -646,7 +661,6 @@ static int dash_init(AVFormatContext *s) if ((ret = avformat_init_output(ctx, &opts)) < 0) return ret; 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); @@ -688,13 +702,24 @@ static int dash_init(AVFormatContext *s) static int dash_write_header(AVFormatContext *s) { DASHContext *c = s->priv_data; - int i, ret; + int i, ret, range_length; for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; if ((ret = avformat_write_header(os->ctx, NULL)) < 0) { dash_free(s); return ret; } + + if ((ret = flush_dynbuf(os, &range_length)) < 0) { + dash_free(s); + return ret; + } + + if (!c->single_file) { + ff_format_io_close(s, &os->out); + } + + os->pos = os->init_range_length = range_length; } ret = write_manifest(s, 0); if (!ret) @@ -803,7 +828,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->packets_written) @@ -821,15 +845,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); @@ -837,26 +852,31 @@ 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->packets_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 = avpriv_io_move(temp_path, full_path); if (ret < 0) break; } - 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->packets_written = 0; + os->pos += range_length; + + // write chunk header + write_styp(os->ctx->pb); } if (c->window_size || (final && c->remove_at_exit)) {