avformat/hlsenc: fix first fragment mp4 do not split bug

fix ticket id: 6888

Tested-by: beloko <beloko@gmail.com>
Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
This commit is contained in:
Steven Liu 2017-12-21 11:14:32 +08:00
parent 58a25aeb8e
commit 8318f60845

View File

@ -352,6 +352,29 @@ static void write_styp(AVIOContext *pb)
ffio_wfourcc(pb, "msix"); 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, static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
VariantStream *vs) { VariantStream *vs) {
@ -677,7 +700,9 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
if ((ret = avio_open_dyn_buf(&oc->pb)) < 0) if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
return ret; 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); av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename);
return ret; return ret;
} }
@ -1404,9 +1429,10 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
av_dict_free(&options); av_dict_free(&options);
if (err < 0) if (err < 0)
return err; return err;
} else } else if (c->segment_type != SEGMENT_TYPE_FMP4) {
if ((err = hlsenc_io_open(s, &oc->pb, oc->filename, &options)) < 0) if ((err = hlsenc_io_open(s, &oc->pb, oc->filename, &options)) < 0)
goto fail; goto fail;
}
if (vs->vtt_basename) { if (vs->vtt_basename) {
set_http_options(s, &options, c); set_http_options(s, &options, c);
if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->filename, &options)) < 0) 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); av_dict_free(&options);
if (c->segment_type == SEGMENT_TYPE_FMP4 && !(c->flags & HLS_SINGLE_FILE)) { if (c->segment_type != SEGMENT_TYPE_FMP4) {
write_styp(oc->pb);
} else {
/* We only require one PAT/PMT per segment. */ /* We only require one PAT/PMT per segment. */
if (oc->oformat->priv_class && oc->priv_data) { if (oc->oformat->priv_class && oc->priv_data) {
char period[21]; char period[21];
@ -1780,7 +1804,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
vs->size = new_start_pos - vs->start_pos; vs->size = new_start_pos - vs->start_pos;
if (!byterange_mode) { 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); avio_flush(oc->pb);
range_length = avio_close_dyn_buf(oc->pb, &buffer); range_length = avio_close_dyn_buf(oc->pb, &buffer);
avio_write(vs->out, buffer, range_length); avio_write(vs->out, buffer, range_length);
@ -1789,6 +1814,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
vs->packets_written = 0; vs->packets_written = 0;
ff_format_io_close(s, &vs->out); ff_format_io_close(s, &vs->out);
hlsenc_io_close(s, &vs->out, vs->base_output_dirname); hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
}
} else { } else {
hlsenc_io_close(s, &oc->pb, oc->filename); hlsenc_io_close(s, &oc->pb, oc->filename);
} }
@ -1807,7 +1833,20 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
vs->number--; 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); ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size);
vs->start_pos = new_start_pos; vs->start_pos = new_start_pos;
if (ret < 0) { if (ret < 0) {
@ -1861,6 +1900,7 @@ static int hls_write_trailer(struct AVFormatContext *s)
AVFormatContext *vtt_oc = NULL; AVFormatContext *vtt_oc = NULL;
char *old_filename = NULL; char *old_filename = NULL;
int i; int i;
int ret = 0;
VariantStream *vs = NULL; VariantStream *vs = NULL;
for (i = 0; i < hls->nb_varstreams; i++) { for (i = 0; i < hls->nb_varstreams; i++) {
@ -1873,11 +1913,25 @@ static int hls_write_trailer(struct AVFormatContext *s)
if (!old_filename) { if (!old_filename) {
return AVERROR(ENOMEM); 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); av_write_trailer(oc);
if (oc->pb) { if (oc->pb) {
vs->size = avio_tell(vs->avf->pb) - vs->start_pos; vs->size = avio_tell(vs->avf->pb) - vs->start_pos;
if (hls->segment_type != SEGMENT_TYPE_FMP4)
ff_format_io_close(s, &oc->pb); ff_format_io_close(s, &oc->pb);
if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) { 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) if ((ret = hls_start(s, vs)) < 0)
goto fail; goto fail;
}
} }
fail: fail: