summaryrefslogtreecommitdiff
path: root/libavformat/hls.c
diff options
context:
space:
mode:
authorAnssi Hannula <anssi.hannula@iki.fi>2013-12-30 11:53:56 +0200
committerAnssi Hannula <anssi.hannula@iki.fi>2014-04-06 17:55:03 +0300
commit6b4b73e75da926aa09dab06789643fb491dfe0ca (patch)
tree924fe3fc5feb5d81993d6ab18bad123f267a889f /libavformat/hls.c
parent8fd6875c83d511dc20390052ccd4d1d567ece152 (diff)
avformat/hls: do not use sequence numbers for packet ordering
As per spec 3.4.3 ("A client MUST NOT assume that segments with the same sequence number in different Media Playlists contain matching content.") we cannot use sequence numbers for packet ordering. This can be seen e.g. in the subtitle streams of bipbop_16x9_variant.m3u8 that have considerably longer segments and therefore different numbering. Since the code now exclusively syncs using timestamps that may wrap, add some additional checking for that. According to the HLS spec all the timestamps should be in 33-bit MPEG format and synced together. v2: cleaner wrap detection v3: further wrap detection improvements Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Diffstat (limited to 'libavformat/hls.c')
-rw-r--r--libavformat/hls.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/libavformat/hls.c b/libavformat/hls.c
index 30df7a9538..ea6b4cf1a1 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -1458,6 +1458,15 @@ static AVRational get_timebase(struct playlist *pls)
return pls->ctx->streams[pls->pkt.stream_index]->time_base;
}
+static int compare_ts_with_wrapdetect(int64_t ts_a, struct playlist *pls_a,
+ int64_t ts_b, struct playlist *pls_b)
+{
+ int64_t scaled_ts_a = av_rescale_q(ts_a, get_timebase(pls_a), MPEG_TIME_BASE_Q);
+ int64_t scaled_ts_b = av_rescale_q(ts_b, get_timebase(pls_b), MPEG_TIME_BASE_Q);
+
+ return av_compare_mod(scaled_ts_a, scaled_ts_b, 1LL << 33);
+}
+
static int hls_read_packet(AVFormatContext *s, AVPacket *pkt)
{
HLSContext *c = s->priv_data;
@@ -1518,26 +1527,19 @@ start:
reset_packet(&pls->pkt);
}
}
- /* Check if this stream still is on an earlier segment number, or
- * has the packet with the lowest dts */
+ /* Check if this stream has the packet with the lowest dts */
if (pls->pkt.data) {
struct playlist *minpls = minplaylist < 0 ?
NULL : c->playlists[minplaylist];
- if (minplaylist < 0 || pls->cur_seq_no < minpls->cur_seq_no) {
+ if (minplaylist < 0) {
minplaylist = i;
- } else if (pls->cur_seq_no == minpls->cur_seq_no) {
+ } else {
int64_t dts = pls->pkt.dts;
int64_t mindts = minpls->pkt.dts;
- AVRational tb = get_timebase( pls);
- AVRational mintb = get_timebase(minpls);
- if (dts == AV_NOPTS_VALUE) {
+ if (dts == AV_NOPTS_VALUE ||
+ (mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, pls, mindts, minpls) < 0))
minplaylist = i;
- } else if (mindts != AV_NOPTS_VALUE) {
- if (av_compare_ts(dts, tb,
- mindts, mintb) < 0)
- minplaylist = i;
- }
}
}
}