|
|
|
@ -101,7 +101,7 @@ struct playlist { |
|
|
|
|
AVFormatContext *parent; |
|
|
|
|
int index; |
|
|
|
|
AVFormatContext *ctx; |
|
|
|
|
AVPacket pkt; |
|
|
|
|
AVPacket *pkt; |
|
|
|
|
int has_noheader_flag; |
|
|
|
|
|
|
|
|
|
/* main demuxer streams associated with this playlist
|
|
|
|
@ -256,7 +256,7 @@ static void free_playlist_list(HLSContext *c) |
|
|
|
|
av_dict_free(&pls->id3_initial); |
|
|
|
|
ff_id3v2_free_extra_meta(&pls->id3_deferred_extra); |
|
|
|
|
av_freep(&pls->init_sec_buf); |
|
|
|
|
av_packet_unref(&pls->pkt); |
|
|
|
|
av_packet_free(&pls->pkt); |
|
|
|
|
av_freep(&pls->pb.buffer); |
|
|
|
|
ff_format_io_close(c->ctx, &pls->input); |
|
|
|
|
pls->input_read_done = 0; |
|
|
|
@ -299,12 +299,17 @@ static struct playlist *new_playlist(HLSContext *c, const char *url, |
|
|
|
|
struct playlist *pls = av_mallocz(sizeof(struct playlist)); |
|
|
|
|
if (!pls) |
|
|
|
|
return NULL; |
|
|
|
|
pls->pkt = av_packet_alloc(); |
|
|
|
|
if (!pls->pkt) { |
|
|
|
|
av_free(pls); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
ff_make_absolute_url(pls->url, sizeof(pls->url), base, url); |
|
|
|
|
if (!pls->url[0]) { |
|
|
|
|
av_packet_free(&pls->pkt); |
|
|
|
|
av_free(pls); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
av_init_packet(&pls->pkt); |
|
|
|
|
pls->seek_timestamp = AV_NOPTS_VALUE; |
|
|
|
|
|
|
|
|
|
pls->is_id3_timestamped = -1; |
|
|
|
@ -2104,26 +2109,26 @@ static int recheck_discard_flags(AVFormatContext *s, int first) |
|
|
|
|
static void fill_timing_for_id3_timestamped_stream(struct playlist *pls) |
|
|
|
|
{ |
|
|
|
|
if (pls->id3_offset >= 0) { |
|
|
|
|
pls->pkt.dts = pls->id3_mpegts_timestamp + |
|
|
|
|
pls->pkt->dts = pls->id3_mpegts_timestamp + |
|
|
|
|
av_rescale_q(pls->id3_offset, |
|
|
|
|
pls->ctx->streams[pls->pkt.stream_index]->time_base, |
|
|
|
|
pls->ctx->streams[pls->pkt->stream_index]->time_base, |
|
|
|
|
MPEG_TIME_BASE_Q); |
|
|
|
|
if (pls->pkt.duration) |
|
|
|
|
pls->id3_offset += pls->pkt.duration; |
|
|
|
|
if (pls->pkt->duration) |
|
|
|
|
pls->id3_offset += pls->pkt->duration; |
|
|
|
|
else |
|
|
|
|
pls->id3_offset = -1; |
|
|
|
|
} else { |
|
|
|
|
/* there have been packets with unknown duration
|
|
|
|
|
* since the last id3 tag, should not normally happen */ |
|
|
|
|
pls->pkt.dts = AV_NOPTS_VALUE; |
|
|
|
|
pls->pkt->dts = AV_NOPTS_VALUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (pls->pkt.duration) |
|
|
|
|
pls->pkt.duration = av_rescale_q(pls->pkt.duration, |
|
|
|
|
pls->ctx->streams[pls->pkt.stream_index]->time_base, |
|
|
|
|
if (pls->pkt->duration) |
|
|
|
|
pls->pkt->duration = av_rescale_q(pls->pkt->duration, |
|
|
|
|
pls->ctx->streams[pls->pkt->stream_index]->time_base, |
|
|
|
|
MPEG_TIME_BASE_Q); |
|
|
|
|
|
|
|
|
|
pls->pkt.pts = AV_NOPTS_VALUE; |
|
|
|
|
pls->pkt->pts = AV_NOPTS_VALUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static AVRational get_timebase(struct playlist *pls) |
|
|
|
@ -2131,7 +2136,7 @@ static AVRational get_timebase(struct playlist *pls) |
|
|
|
|
if (pls->is_id3_timestamped) |
|
|
|
|
return MPEG_TIME_BASE_Q; |
|
|
|
|
|
|
|
|
|
return pls->ctx->streams[pls->pkt.stream_index]->time_base; |
|
|
|
|
return pls->ctx->streams[pls->pkt->stream_index]->time_base; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int compare_ts_with_wrapdetect(int64_t ts_a, struct playlist *pls_a, |
|
|
|
@ -2155,25 +2160,25 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
struct playlist *pls = c->playlists[i]; |
|
|
|
|
/* Make sure we've got one buffered packet from each open playlist
|
|
|
|
|
* stream */ |
|
|
|
|
if (pls->needed && !pls->pkt.data) { |
|
|
|
|
if (pls->needed && !pls->pkt->data) { |
|
|
|
|
while (1) { |
|
|
|
|
int64_t ts_diff; |
|
|
|
|
AVRational tb; |
|
|
|
|
ret = av_read_frame(pls->ctx, &pls->pkt); |
|
|
|
|
ret = av_read_frame(pls->ctx, pls->pkt); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
if (!avio_feof(&pls->pb) && ret != AVERROR_EOF) |
|
|
|
|
return ret; |
|
|
|
|
break; |
|
|
|
|
} else { |
|
|
|
|
/* stream_index check prevents matching picture attachments etc. */ |
|
|
|
|
if (pls->is_id3_timestamped && pls->pkt.stream_index == 0) { |
|
|
|
|
if (pls->is_id3_timestamped && pls->pkt->stream_index == 0) { |
|
|
|
|
/* audio elementary streams are id3 timestamped */ |
|
|
|
|
fill_timing_for_id3_timestamped_stream(pls); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (c->first_timestamp == AV_NOPTS_VALUE && |
|
|
|
|
pls->pkt.dts != AV_NOPTS_VALUE) |
|
|
|
|
c->first_timestamp = av_rescale_q(pls->pkt.dts, |
|
|
|
|
pls->pkt->dts != AV_NOPTS_VALUE) |
|
|
|
|
c->first_timestamp = av_rescale_q(pls->pkt->dts, |
|
|
|
|
get_timebase(pls), AV_TIME_BASE_Q); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2181,35 +2186,35 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
if (pls->seek_stream_index < 0 || |
|
|
|
|
pls->seek_stream_index == pls->pkt.stream_index) { |
|
|
|
|
pls->seek_stream_index == pls->pkt->stream_index) { |
|
|
|
|
|
|
|
|
|
if (pls->pkt.dts == AV_NOPTS_VALUE) { |
|
|
|
|
if (pls->pkt->dts == AV_NOPTS_VALUE) { |
|
|
|
|
pls->seek_timestamp = AV_NOPTS_VALUE; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tb = get_timebase(pls); |
|
|
|
|
ts_diff = av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE, |
|
|
|
|
ts_diff = av_rescale_rnd(pls->pkt->dts, AV_TIME_BASE, |
|
|
|
|
tb.den, AV_ROUND_DOWN) - |
|
|
|
|
pls->seek_timestamp; |
|
|
|
|
if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY || |
|
|
|
|
pls->pkt.flags & AV_PKT_FLAG_KEY)) { |
|
|
|
|
pls->pkt->flags & AV_PKT_FLAG_KEY)) { |
|
|
|
|
pls->seek_timestamp = AV_NOPTS_VALUE; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
av_packet_unref(&pls->pkt); |
|
|
|
|
av_packet_unref(pls->pkt); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/* Check if this stream has the packet with the lowest dts */ |
|
|
|
|
if (pls->pkt.data) { |
|
|
|
|
if (pls->pkt->data) { |
|
|
|
|
struct playlist *minpls = minplaylist < 0 ? |
|
|
|
|
NULL : c->playlists[minplaylist]; |
|
|
|
|
if (minplaylist < 0) { |
|
|
|
|
minplaylist = i; |
|
|
|
|
} else { |
|
|
|
|
int64_t dts = pls->pkt.dts; |
|
|
|
|
int64_t mindts = minpls->pkt.dts; |
|
|
|
|
int64_t dts = pls->pkt->dts; |
|
|
|
|
int64_t mindts = minpls->pkt->dts; |
|
|
|
|
|
|
|
|
|
if (dts == AV_NOPTS_VALUE || |
|
|
|
|
(mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, pls, mindts, minpls) < 0)) |
|
|
|
@ -2226,7 +2231,7 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
|
|
|
|
|
ret = update_streams_from_subdemuxer(s, pls); |
|
|
|
|
if (ret < 0) { |
|
|
|
|
av_packet_unref(&pls->pkt); |
|
|
|
|
av_packet_unref(pls->pkt); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2247,17 +2252,17 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
update_noheader_flag(s); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (pls->pkt.stream_index >= pls->n_main_streams) { |
|
|
|
|
if (pls->pkt->stream_index >= pls->n_main_streams) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "stream index inconsistency: index %d, %d main streams, %d subdemuxer streams\n", |
|
|
|
|
pls->pkt.stream_index, pls->n_main_streams, pls->ctx->nb_streams); |
|
|
|
|
av_packet_unref(&pls->pkt); |
|
|
|
|
pls->pkt->stream_index, pls->n_main_streams, pls->ctx->nb_streams); |
|
|
|
|
av_packet_unref(pls->pkt); |
|
|
|
|
return AVERROR_BUG; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ist = pls->ctx->streams[pls->pkt.stream_index]; |
|
|
|
|
st = pls->main_streams[pls->pkt.stream_index]; |
|
|
|
|
ist = pls->ctx->streams[pls->pkt->stream_index]; |
|
|
|
|
st = pls->main_streams[pls->pkt->stream_index]; |
|
|
|
|
|
|
|
|
|
av_packet_move_ref(pkt, &pls->pkt); |
|
|
|
|
av_packet_move_ref(pkt, pls->pkt); |
|
|
|
|
pkt->stream_index = st->index; |
|
|
|
|
|
|
|
|
|
if (pkt->dts != AV_NOPTS_VALUE) |
|
|
|
@ -2333,7 +2338,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, |
|
|
|
|
pls->input_read_done = 0; |
|
|
|
|
ff_format_io_close(pls->parent, &pls->input_next); |
|
|
|
|
pls->input_next_requested = 0; |
|
|
|
|
av_packet_unref(&pls->pkt); |
|
|
|
|
av_packet_unref(pls->pkt); |
|
|
|
|
pls->pb.eof_reached = 0; |
|
|
|
|
/* Clear any buffered data */ |
|
|
|
|
pls->pb.buf_end = pls->pb.buf_ptr = pls->pb.buffer; |
|
|
|
|