[FFmpeg-devel] [PATCH 08/19] avformat/hls: pass segment offset info to hls_id3_audio demuxer

Anssi Hannula anssi.hannula at iki.fi
Fri Jan 3 15:21:32 CET 2014


HLS provides MPEG TS timestamps via ID3 tags in the beginning of each
segment of elementary audio streams. This is handled by the new
hls_id3_audio demuxer, but it requires us to pass along the segment
switch offsets via AVOptions.

Signed-off-by: Anssi Hannula <anssi.hannula at iki.fi>
---

I'll fix the wrongly added whitespace before commit.

 libavformat/hls.c | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index 42fbc3e..a211941 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -95,6 +95,7 @@ struct playlist {
     int needed, cur_needed;
     int cur_seq_no;
     int64_t cur_seg_offset;
+    int64_t next_seg_bytepos;
     int64_t last_load_time;
 
     char key_url[MAX_URL_SIZE];
@@ -234,6 +235,7 @@ static struct playlist *new_playlist(HLSContext *c, const char *url,
         return NULL;
     reset_packet(&pls->pkt);
     ff_make_absolute_url(pls->url, sizeof(pls->url), base, url);
+
     dynarray_add(&c->playlists, &c->n_playlists, pls);
     return pls;
 }
@@ -596,6 +598,15 @@ fail:
     return ret;
 }
 
+static void set_audio_id3_tag_offset(struct playlist *pls)
+{
+    if (pls->ctx && pls->ctx->iformat && pls->ctx->iformat->priv_class
+        && !strcmp(pls->ctx->iformat->name, "hls_id3_audio")) {
+        av_opt_set_int(pls->ctx->priv_data, "segment_end", pls->next_seg_bytepos, 0);
+        av_log(pls->parent, AV_LOG_DEBUG, "Next ID3 offset set to %"PRId64"\n", pls->next_seg_bytepos);
+    }
+}
+
 static int open_input(HLSContext *c, struct playlist *pls)
 {
     AVDictionary *opts = NULL;
@@ -686,6 +697,10 @@ static int open_input(HLSContext *c, struct playlist *pls)
             pls->input = NULL;
         }
     }
+    if (ret == 0) {
+        pls->next_seg_bytepos = pls->pb.pos + (seg->size >= 0 ? seg->size : ffurl_size(pls->input));
+        set_audio_id3_tag_offset(pls);
+    }
 
 cleanup:
     av_dict_free(&opts);
@@ -979,6 +994,10 @@ static int hls_read_header(AVFormatContext *s)
         if (ret < 0)
             goto fail;
 
+        /* This was not set by open_input since the demuxer was not opened yet.
+         * We could put this in opts above but it would be just more code. */
+        set_audio_id3_tag_offset(pls);
+
         pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;
         ret = avformat_find_stream_info(pls->ctx, NULL);
         if (ret < 0)
@@ -993,6 +1012,7 @@ static int hls_read_header(AVFormatContext *s)
                 goto fail;
             }
             st->id = i;
+
             avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den);
             avcodec_copy_context(st->codec, pls->ctx->streams[j]->codec);
         }
@@ -1100,7 +1120,7 @@ start:
         if (pls->needed && !pls->pkt.data) {
             while (1) {
                 int64_t ts_diff;
-                AVStream *st;
+                AVRational tb;
                 ret = av_read_frame(pls->ctx, &pls->pkt);
                 if (ret < 0) {
                     if (!url_feof(&pls->pb) && ret != AVERROR_EOF)
@@ -1108,6 +1128,7 @@ start:
                     reset_packet(&pls->pkt);
                     break;
                 } else {
+
                     if (c->first_timestamp == AV_NOPTS_VALUE &&
                         pls->pkt.dts       != AV_NOPTS_VALUE)
                         c->first_timestamp = av_rescale_q(pls->pkt.dts,
@@ -1123,9 +1144,9 @@ start:
                     break;
                 }
 
-                st = pls->ctx->streams[pls->pkt.stream_index];
+                tb = pls->ctx->streams[pls->pkt.stream_index]->time_base;
                 ts_diff = av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE,
-                                         st->time_base.den, AV_ROUND_DOWN) -
+                                         tb.den, AV_ROUND_DOWN) -
                           c->seek_timestamp;
                 if (ts_diff >= 0 && (c->seek_flags  & AVSEEK_FLAG_ANY ||
                                      pls->pkt.flags & AV_PKT_FLAG_KEY)) {
@@ -1148,6 +1169,8 @@ start:
                 int64_t mindts  = minpls->pkt.dts;
                 AVStream *st    =    pls->ctx->streams[pls->pkt.stream_index];
                 AVStream *minst = minpls->ctx->streams[minpls->pkt.stream_index];
+                AVRational tb    =    pls->ctx->streams[   pls->pkt.stream_index]->time_base;
+                AVRational mintb = minpls->ctx->streams[minpls->pkt.stream_index]->time_base;
 
                 if (dts == AV_NOPTS_VALUE) {
                     minplaylist = i;
@@ -1157,8 +1180,8 @@ start:
                     if (minst->start_time != AV_NOPTS_VALUE)
                         mindts -= minst->start_time;
 
-                    if (av_compare_ts(dts, st->time_base,
-                                      mindts, minst->time_base) < 0)
+                    if (av_compare_ts(dts, tb,
+                                      mindts, mintb) < 0)
                         minplaylist = i;
                 }
             }
@@ -1229,6 +1252,9 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
         pls->pb.buf_end = pls->pb.buf_ptr = pls->pb.buffer;
         /* Reset the pos, to let the mpegts demuxer know we've seeked. */
         pls->pb.pos = 0;
+        /* Set current segment to end immediately for audio demuxer */
+        pls->next_seg_bytepos = 0;
+        set_audio_id3_tag_offset(pls);
 
         /* Locate the segment that contains the target timestamp */
         for (j = 0; j < pls->n_segments; j++) {
-- 
1.8.1.5



More information about the ffmpeg-devel mailing list