[FFmpeg-devel] [PATCH] avformat/hlsenc: merge mpegts and fmp4 workflow to one workflow
Liu Steven
lq at chinaffmpeg.org
Wed Jul 31 11:06:55 EEST 2019
ignore this patch please, i will resend the v2 version.
> 在 2019年7月31日,下午2:38,Steven Liu <lq at chinaffmpeg.org> 写道:
>
> write mpegts or fmp4 context into buffer, and flush the buffer into
> output file when split fragment. merge two format split workflow into
> one workflow
>
> Signed-off-by: Steven Liu <lq at chinaffmpeg.org>
> ---
> libavformat/hlsenc.c | 207 ++++++++++++++++++++-----------------------
> 1 file changed, 95 insertions(+), 112 deletions(-)
>
> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
> index 51310fb528..68d9201a5e 100644
> --- a/libavformat/hlsenc.c
> +++ b/libavformat/hlsenc.c
> @@ -815,7 +815,7 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
> vs->start_pos = 0;
> vs->new_start = 1;
>
> - if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> + if (hls->segment_type == SEGMENT_TYPE_FMP4 && hls->max_seg_size > 0) {
> if (hls->http_persistent > 0) {
> //TODO: Support fragment fmp4 for http persistent in HLS muxer.
> av_log(s, AV_LOG_WARNING, "http persistent mode is currently unsupported for fragment mp4 in the HLS muxer.\n");
> @@ -824,34 +824,38 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
> av_log(s, AV_LOG_WARNING, "Multi-file byterange mode is currently unsupported in the HLS muxer.\n");
> return AVERROR_PATCHWELCOME;
> }
> + }
>
> - vs->packets_written = 0;
> - vs->init_range_length = 0;
> - set_http_options(s, &options, hls);
> - if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
> - return ret;
> + vs->packets_written = 0;
> + vs->init_range_length = 0;
> + set_http_options(s, &options, hls);
> + if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
> + return ret;
>
> + if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> if (byterange_mode) {
> ret = hlsenc_io_open(s, &vs->out, vs->basename, &options);
> } else {
> ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options);
> }
> - av_dict_free(&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;
> + }
> +
> + if (hls->format_options_str) {
> + ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
> if (ret < 0) {
> - av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename);
> + av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n",
> + hls->format_options_str);
> return ret;
> }
> + }
>
> - if (hls->format_options_str) {
> - ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
> - if (ret < 0) {
> - av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n",
> - hls->format_options_str);
> - return ret;
> - }
> - }
> -
> - av_dict_copy(&options, hls->format_options, 0);
> + av_dict_copy(&options, hls->format_options, 0);
> + if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> av_dict_set(&options, "fflags", "-autobsf", 0);
> av_dict_set(&options, "movflags", "+frag_custom+dash+delay_moov", AV_DICT_APPEND);
> ret = avformat_init_output(oc, &options);
> @@ -862,9 +866,9 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
> av_dict_free(&options);
> return AVERROR(EINVAL);
> }
> - avio_flush(oc->pb);
> - av_dict_free(&options);
> }
> + avio_flush(oc->pb);
> + av_dict_free(&options);
> return 0;
> }
>
> @@ -1435,7 +1439,6 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
> {
> HLSContext *hls = s->priv_data;
> HLSSegment *en;
> - AVFormatContext *oc = vs->avf;
> int target_duration = 0;
> int ret = 0;
> char temp_filename[MAX_URL_SIZE];
> @@ -1471,7 +1474,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
>
> set_http_options(s, &options, hls);
> snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", vs->m3u8_name);
> - if ((ret = hlsenc_io_open(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &oc->pb, temp_filename, &options)) < 0) {
> + if ((ret = hlsenc_io_open(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &vs->out, temp_filename, &options)) < 0) {
> if (hls->ignore_io_errors)
> ret = 0;
> goto fail;
> @@ -1483,33 +1486,33 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
> }
>
> vs->discontinuity_set = 0;
> - ff_hls_write_playlist_header((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, hls->version, hls->allowcache,
> + ff_hls_write_playlist_header((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, hls->version, hls->allowcache,
> target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY);
>
> if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ){
> - avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-DISCONTINUITY\n");
> + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "#EXT-X-DISCONTINUITY\n");
> vs->discontinuity_set = 1;
> }
> if (vs->has_video && (hls->flags & HLS_INDEPENDENT_SEGMENTS)) {
> - avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-INDEPENDENT-SEGMENTS\n");
> + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "#EXT-X-INDEPENDENT-SEGMENTS\n");
> }
> for (en = vs->segments; en; en = en->next) {
> if ((hls->encrypt || hls->key_info_file) && (!key_uri || strcmp(en->key_uri, key_uri) ||
> av_strcasecmp(en->iv_string, iv_string))) {
> - avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri);
> + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri);
> if (*en->iv_string)
> - avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, ",IV=0x%s", en->iv_string);
> - avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "\n");
> + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, ",IV=0x%s", en->iv_string);
> + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, "\n");
> key_uri = en->key_uri;
> iv_string = en->iv_string;
> }
>
> if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == vs->segments)) {
> - ff_hls_write_init_file((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename,
> + ff_hls_write_init_file((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename,
> hls->flags & HLS_SINGLE_FILE, vs->init_range_length, 0);
> }
>
> - ret = ff_hls_write_file_entry((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, en->discont, byterange_mode,
> + ret = ff_hls_write_file_entry((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out, en->discont, byterange_mode,
> en->duration, hls->flags & HLS_ROUND_DURATIONS,
> en->size, en->pos, vs->baseurl,
> en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
> @@ -1519,7 +1522,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
> }
>
> if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
> - ff_hls_write_end_list((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb);
> + ff_hls_write_end_list((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : vs->out);
>
> if (vs->vtt_m3u8_name) {
> snprintf(temp_vtt_filename, sizeof(temp_vtt_filename), use_temp_file ? "%s.tmp" : "%s", vs->vtt_m3u8_name);
> @@ -1546,7 +1549,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
>
> fail:
> av_dict_free(&options);
> - hlsenc_io_close(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &oc->pb, temp_filename);
> + hlsenc_io_close(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &vs->out, temp_filename);
> hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name);
> if (use_temp_file) {
> ff_rename(temp_filename, vs->m3u8_name, s);
> @@ -1713,23 +1716,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
> av_dict_free(&options);
> if (err < 0)
> return err;
> - } else if (c->segment_type != SEGMENT_TYPE_FMP4) {
> - if ((err = hlsenc_io_open(s, &oc->pb, oc->url, &options)) < 0) {
> - if (c->ignore_io_errors)
> - err = 0;
> - goto fail;
> - }
> }
> - if (vs->vtt_basename) {
> - set_http_options(s, &options, c);
> - if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) {
> - if (c->ignore_io_errors)
> - err = 0;
> - goto fail;
> - }
> - }
> - av_dict_free(&options);
> -
> if (c->segment_type != SEGMENT_TYPE_FMP4) {
> /* We only require one PAT/PMT per segment. */
> if (oc->oformat->priv_class && oc->priv_data) {
> @@ -1741,7 +1728,23 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
> av_opt_set(oc->priv_data, "sdt_period", period, 0);
> av_opt_set(oc->priv_data, "pat_period", period, 0);
> }
> + if (c->flags & HLS_SINGLE_FILE) {
> + if ((err = hlsenc_io_open(s, &vs->out, oc->url, &options)) < 0) {
> + if (c->ignore_io_errors)
> + err = 0;
> + goto fail;
> + }
> + }
> }
> + if (vs->vtt_basename) {
> + set_http_options(s, &options, c);
> + if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) {
> + if (c->ignore_io_errors)
> + err = 0;
> + goto fail;
> + }
> + }
> + av_dict_free(&options);
>
> if (vs->vtt_basename) {
> err = avformat_write_header(vtt_oc,NULL);
> @@ -2343,20 +2346,12 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> int64_t new_start_pos;
> int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
>
> - av_write_frame(vs->avf, NULL); /* Flush any buffered data */
> -
> - new_start_pos = avio_tell(vs->avf->pb);
> -
> - if (hls->segment_type != SEGMENT_TYPE_FMP4) {
> - avio_flush(oc->pb);
> - vs->size = new_start_pos - vs->start_pos;
> - } else {
> - vs->size = new_start_pos;
> - }
> -
> + av_write_frame(oc, NULL); /* Flush any buffered data */
> + new_start_pos = avio_tell(oc->pb);
> + vs->size = new_start_pos - vs->start_pos;
> + avio_flush(oc->pb);
> 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);
> av_free(buffer);
> @@ -2365,14 +2360,10 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> vs->packets_written = 0;
> vs->start_pos = range_length;
> if (!byterange_mode) {
> - ff_format_io_close(s, &vs->out);
> +// ff_format_io_close(s, &vs->out);
> hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
> }
> }
> - } else {
> - if (!byterange_mode) {
> - hlsenc_io_close(s, &oc->pb, oc->url);
> - }
> }
> if (!byterange_mode) {
> if (vs->vtt_avf) {
> @@ -2387,32 +2378,32 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>
> // look to rename the asset name
> if (use_temp_file) {
> - if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0))
> - if ((vs->avf->oformat->priv_class && vs->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4)
> - av_opt_set(vs->avf->priv_data, "mpegts_flags", "resend_headers", 0);
> + av_dict_set(&options, "mpegts_flags", "resend_headers", 0);
> }
>
> - if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> - if (hls->flags & HLS_SINGLE_FILE) {
> - ret = flush_dynbuf(vs, &range_length);
> - if (ret < 0) {
> - return ret;
> - }
> - vs->size = range_length;
> - } else {
> - set_http_options(s, &options, hls);
> - ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options);
> + if (hls->flags & HLS_SINGLE_FILE) {
> + ret = flush_dynbuf(vs, &range_length);
> + if (ret < 0) {
> + return ret;
> + }
> + vs->size = range_length;
> + } else {
> + set_http_options(s, &options, hls);
> + if ((hls->max_seg_size > 0 && (vs->size >= hls->max_seg_size)) || !byterange_mode) {
> + ret = hlsenc_io_open(s, &vs->out, oc->url, &options);
> if (ret < 0) {
> av_log(s, hls->ignore_io_errors ? AV_LOG_WARNING : AV_LOG_ERROR,
> - "Failed to open file '%s'\n", vs->avf->url);
> + "Failed to open file '%s'\n", oc->url);
> return hls->ignore_io_errors ? 0 : ret;
> }
> - write_styp(vs->out);
> + if (hls->segment_type == SEGMENT_TYPE_FMP4) {
> + write_styp(vs->out);
> + }
> ret = flush_dynbuf(vs, &range_length);
> if (ret < 0) {
> return ret;
> }
> - ff_format_io_close(s, &vs->out);
> + hlsenc_io_close(s, &vs->out, oc->url);
> }
> }
>
> @@ -2420,7 +2411,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> hls_rename_temp_file(s, oc);
> }
>
> - old_filename = av_strdup(vs->avf->url);
> + old_filename = av_strdup(oc->url);
> if (!old_filename) {
> return AVERROR(ENOMEM);
> }
> @@ -2435,11 +2426,6 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> }
> }
>
> - if (hls->segment_type != SEGMENT_TYPE_FMP4) {
> - vs->start_pos = new_start_pos;
> - } else {
> - vs->start_pos += vs->size;
> - }
> // if we're building a VOD playlist, skip writing the manifest multiple times, and just wait until the end
> if (hls->pl_type != PLAYLIST_TYPE_VOD) {
> if ((ret = hls_window(s, 0, vs)) < 0) {
> @@ -2449,8 +2435,10 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
>
> if (hls->flags & HLS_SINGLE_FILE) {
> vs->number++;
> + vs->start_pos += vs->size;
> } else if (hls->max_seg_size > 0) {
> - if (vs->start_pos >= hls->max_seg_size) {
> + vs->start_pos = new_start_pos;
> + if (vs->size >= hls->max_seg_size) {
> vs->sequence++;
> sls_flag_file_rename(hls, vs, old_filename);
> ret = hls_start(s, vs);
> @@ -2461,6 +2449,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> }
> vs->number++;
> } else {
> + vs->start_pos = new_start_pos;
> sls_flag_file_rename(hls, vs, old_filename);
> ret = hls_start(s, vs);
> }
> @@ -2475,13 +2464,12 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
> vs->packets_written++;
> if (oc->pb) {
> ret = ff_write_chained(oc, stream_index, pkt, s, 0);
> + vs->video_keyframe_size += pkt->size;
> if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) {
> - vs->video_keyframe_size = avio_tell(oc->pb) - vs->video_lastpos;
> - vs->video_keyframe_pos = vs->start_pos;
> + vs->video_keyframe_size = avio_tell(oc->pb);
> } else {
> - vs->video_lastpos = avio_tell(oc->pb);
> + vs->video_keyframe_pos = avio_tell(vs->out);
> }
> -
> if (hls->ignore_io_errors)
> ret = 0;
> }
> @@ -2530,10 +2518,11 @@ static int hls_write_trailer(struct AVFormatContext *s)
> int i;
> int ret = 0;
> VariantStream *vs = NULL;
> + AVDictionary *options = NULL;
> + int range_length, byterange_mode;
>
> for (i = 0; i < hls->nb_varstreams; i++) {
> vs = &hls->var_streams[i];
> -
> oc = vs->avf;
> vtt_oc = vs->vtt_avf;
> old_filename = av_strdup(vs->avf->url);
> @@ -2546,7 +2535,6 @@ static int hls_write_trailer(struct AVFormatContext *s)
> int range_length = 0;
> if (!vs->init_range_length) {
> uint8_t *buffer = NULL;
> - int range_length, byterange_mode;
> av_write_frame(vs->avf, NULL); /* Flush any buffered data */
> avio_flush(oc->pb);
>
> @@ -2563,21 +2551,23 @@ static int hls_write_trailer(struct AVFormatContext *s)
> hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
> }
> }
> - if (!(hls->flags & HLS_SINGLE_FILE)) {
> - ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL);
> - if (ret < 0) {
> - av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->url);
> - goto failed;
> - }
> - write_styp(vs->out);
> - }
> - ret = flush_dynbuf(vs, &range_length);
> + }
> + if (!(hls->flags & HLS_SINGLE_FILE)) {
> + set_http_options(s, &options, hls);
> + ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options);
> if (ret < 0) {
> + av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->url);
> goto failed;
> }
> - vs->size = range_length;
> - ff_format_io_close(s, &vs->out);
> + if (hls->segment_type == SEGMENT_TYPE_FMP4)
> + write_styp(vs->out);
> }
> + ret = flush_dynbuf(vs, &range_length);
> + if (ret < 0)
> + goto failed;
> +
> + vs->size = range_length;
> + hlsenc_io_close(s, &vs->out, vs->avf->url);
>
> failed:
> av_write_trailer(oc);
> @@ -2587,12 +2577,6 @@ failed:
> use_temp_file = proto && !strcmp(proto, "file") && (hls->flags & HLS_TEMP_FILE);
> }
>
> - if (oc->pb) {
> - if (hls->segment_type != SEGMENT_TYPE_FMP4) {
> - vs->size = avio_tell(vs->avf->pb) - vs->start_pos;
> - hlsenc_io_close(s, &vs->avf->pb, vs->avf->url);
> - }
> -
> // rename that segment from .tmp to the real one
> if (use_temp_file && !(hls->flags & HLS_SINGLE_FILE)) {
> hls_rename_temp_file(s, oc);
> @@ -2606,7 +2590,6 @@ failed:
>
> /* after av_write_trailer, then duration + 1 duration per packet */
> hls_append_segment(s, hls, vs, vs->duration + vs->dpp, vs->start_pos, vs->size);
> - }
>
> sls_flag_file_rename(hls, vs, old_filename);
>
> --
> 2.17.2 (Apple Git-113)
>
More information about the ffmpeg-devel
mailing list