[FFmpeg-devel] [PATCH 1/4] avformat/hlsenc: fix first fragment mp4 do not split bug
Karthick Jeyapal
kjeyapal at akamai.com
Tue Dec 19 05:42:27 EET 2017
On 12/18/17 2:17 PM, Steven Liu wrote:
> fix ticket id: 6888
>
> Signed-off-by: Steven Liu <lq at chinaffmpeg.org>
> ---
> libavformat/hlsenc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 62 insertions(+), 10 deletions(-)
>
> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
> index e3442c368f..f51fec1030 100644
> --- a/libavformat/hlsenc.c
> +++ b/libavformat/hlsenc.c
> @@ -352,6 +352,29 @@ static void write_styp(AVIOContext *pb)
> ffio_wfourcc(pb, "msix");
> }
>
> +static int flush_dynbuf(VariantStream *vs, int *range_length)
> +{
> + AVFormatContext *ctx = vs->avf;
> + uint8_t *buffer;
> +
> + if (!ctx->pb) {
> + return AVERROR(EINVAL);
> + }
> +
> + // flush
> + av_write_frame(ctx, NULL);
> + avio_flush(ctx->pb);
> +
> + // write out to file
> + *range_length = avio_close_dyn_buf(ctx->pb, &buffer);
> + ctx->pb = NULL;
> + avio_write(vs->out, buffer, *range_length);
> + av_free(buffer);
> +
> + // re-open buffer
> + return avio_open_dyn_buf(&ctx->pb);
> +}
> +
> static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
> VariantStream *vs) {
>
> @@ -677,7 +700,9 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
> if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
> return ret;
>
> - if ((ret = s->io_open(s, &vs->out, vs->base_output_dirname, AVIO_FLAG_WRITE, &options)) < 0) {
> + ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options);
> + av_dict_free(&options);
> + if (ret < 0) {
> av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename);
> return ret;
> }
> @@ -1404,9 +1429,10 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
> av_dict_free(&options);
> if (err < 0)
> return err;
> - } else
> + } else if (c->segment_type != SEGMENT_TYPE_FMP4) {
> if ((err = hlsenc_io_open(s, &oc->pb, oc->filename, &options)) < 0)
> goto fail;
> + }
> if (vs->vtt_basename) {
> set_http_options(s, &options, c);
> if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->filename, &options)) < 0)
> @@ -1414,9 +1440,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
> }
> av_dict_free(&options);
>
> - if (c->segment_type == SEGMENT_TYPE_FMP4 && !(c->flags & HLS_SINGLE_FILE)) {
> - write_styp(oc->pb);
> - } else {
> + if (c->segment_type != SEGMENT_TYPE_FMP4) {
> /* We only require one PAT/PMT per segment. */
> if (oc->oformat->priv_class && oc->priv_data) {
> char period[21];
> @@ -1780,7 +1804,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> vs->size = new_start_pos - vs->start_pos;
>
> if (!byterange_mode) {
> - if (hls->segment_type == SEGMENT_TYPE_FMP4 && !vs->init_range_length) {
> + if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> + if (!vs->init_range_length) {
> avio_flush(oc->pb);
> range_length = avio_close_dyn_buf(oc->pb, &buffer);
> avio_write(vs->out, buffer, range_length);
> @@ -1789,6 +1814,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> vs->packets_written = 0;
> ff_format_io_close(s, &vs->out);
> hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
> + }
> } else {
> hlsenc_io_close(s, &oc->pb, oc->filename);
> }
> @@ -1807,7 +1833,20 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> vs->number--;
> }
>
> - if (!vs->fmp4_init_mode || byterange_mode)
> + if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> + ret = hlsenc_io_open(s, &vs->out, vs->avf->filename, NULL);
Will it be better if you call "set_http_options()" here itself, instead
of a separate patch 4/4? In that way this patch would be self contained.
> + if (ret < 0) {
> + av_log(NULL, AV_LOG_ERROR, "Failed to open file '%s'\n",
> + vs->avf->filename);
> + return ret;
> + }
> + write_styp(vs->out);
> + ret = flush_dynbuf(vs, &range_length);
> + if (ret < 0) {
> + return ret;
> + }
> + ff_format_io_close(s, &vs->out);
Again is it better to call hlsenc_io_close() here itself instead of
patch 3/4. Again just from self-containment perspective.
> + }
> ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size);
> vs->start_pos = new_start_pos;
> if (ret < 0) {
> @@ -1861,6 +1900,7 @@ static int hls_write_trailer(struct AVFormatContext *s)
> AVFormatContext *vtt_oc = NULL;
> char *old_filename = NULL;
> int i;
> + int ret = 0;
> VariantStream *vs = NULL;
>
> for (i = 0; i < hls->nb_varstreams; i++) {
> @@ -1873,11 +1913,25 @@ static int hls_write_trailer(struct AVFormatContext *s)
> if (!old_filename) {
> return AVERROR(ENOMEM);
> }
> -
> + if ( hls->segment_type == SEGMENT_TYPE_FMP4) {
> + int range_length = 0;
> + ret = hlsenc_io_open(s, &vs->out, vs->avf->filename, NULL);
> + if (ret < 0) {
> + av_log(NULL, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->filename);
> + return AVERROR(ENOENT);
> + }
> + write_styp(vs->out);
> + ret = flush_dynbuf(vs, &range_length);
> + if (ret < 0) {
> + return ret;
> + }
> + ff_format_io_close(s, &vs->out);
> + }
Will it make sense it make this code as a separate function in order to
avoid code repetition?
>
> av_write_trailer(oc);
> if (oc->pb) {
> vs->size = avio_tell(vs->avf->pb) - vs->start_pos;
> + if (hls->segment_type != SEGMENT_TYPE_FMP4)
> ff_format_io_close(s, &oc->pb);
>
> if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) {
> @@ -2238,10 +2292,8 @@ static int hls_init(AVFormatContext *s)
> }
> }
>
> - if (hls->segment_type != SEGMENT_TYPE_FMP4 || hls->flags & HLS_SINGLE_FILE) {
> if ((ret = hls_start(s, vs)) < 0)
> goto fail;
> - }
> }
>
> fail:
Thanks,
Karthick
More information about the ffmpeg-devel
mailing list