diff mbox

[FFmpeg-devel,1/4] avformat/hlsenc: fix first fragment mp4 do not split bug

Message ID 20171218084705.13885-1-lq@chinaffmpeg.org
State Accepted
Commit 8318f60845bbbc4d33a39eee45e4daff0e5dacfb
Headers show

Commit Message

Steven Liu Dec. 18, 2017, 8:47 a.m. UTC
fix ticket id: 6888

Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
---
 libavformat/hlsenc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 62 insertions(+), 10 deletions(-)

Comments

Jeyapal, Karthick Dec. 19, 2017, 3:42 a.m. UTC | #1
On 12/18/17 2:17 PM, Steven Liu wrote:
> fix ticket id: 6888
>
> Signed-off-by: Steven Liu <lq@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
Steven Liu Dec. 19, 2017, 3:51 a.m. UTC | #2
> On 19 Dec 2017, at 11:42, Karthick Jeyapal <kjeyapal@akamai.com> wrote:
> 
> 
> 
> On 12/18/17 2:17 PM, Steven Liu wrote:
>> fix ticket id: 6888
>> 
>> Signed-off-by: Steven Liu <lq@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.
set_http_options is add option to http operation, so separate two patches.
And this patch just fix ticket
>> +            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.
Replace API to hlsenc_io_close is a new operation, so separate two patch
And this patch just fix ticket
>> +        }
>>              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?
That is optimize operation, this patch just fix ticket, so i will send a new patch to merge two workflow to on function.

Thanks

Steven
>>        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
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Steven Liu Dec. 21, 2017, 3:16 a.m. UTC | #3
> On 19 Dec 2017, at 11:51, 刘歧 <lq@chinaffmpeg.org> wrote:
> 
> 
> 
>> On 19 Dec 2017, at 11:42, Karthick Jeyapal <kjeyapal@akamai.com> wrote:
>> 
>> 
>> 
>> On 12/18/17 2:17 PM, Steven Liu wrote:
>>> fix ticket id: 6888
>>> 
>>> Signed-off-by: Steven Liu <lq@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.
> set_http_options is add option to http operation, so separate two patches.
> And this patch just fix ticket
>>> +            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.
> Replace API to hlsenc_io_close is a new operation, so separate two patch
> And this patch just fix ticket
>>> +        }
>>>             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?
> That is optimize operation, this patch just fix ticket, so i will send a new patch to merge two workflow to on function.
> 
> Thanks
> 
> Steven
>>>       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
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

pushed

Thanks
diff mbox

Patch

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);
+            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);
+        }
             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);
+    }
 
     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: