aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat/mpegts.c
diff options
context:
space:
mode:
authorAlex Converse <alex.converse@gmail.com>2011-10-11 14:49:59 -0700
committerAlex Converse <alex.converse@gmail.com>2011-10-28 14:54:14 -0700
commitca65932bbf2a4851838f84456050e2972091950d (patch)
tree41e607720cf8c91489873e6ddc578cb8d4176388 /libavformat/mpegts.c
parentc5302670244bd587d6ff3b6e8ef73451d1c01211 (diff)
downloadffmpeg-ca65932bbf2a4851838f84456050e2972091950d.tar.gz
mpegts: MP4 SL support
Diffstat (limited to 'libavformat/mpegts.c')
-rw-r--r--libavformat/mpegts.c159
1 files changed, 138 insertions, 21 deletions
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 4c9462cead..5fa82dc21a 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -28,6 +28,7 @@
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavcodec/bytestream.h"
+#include "libavcodec/get_bits.h"
#include "avformat.h"
#include "mpegts.h"
#include "internal.h"
@@ -175,6 +176,7 @@ typedef struct PESContext {
int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */
uint8_t header[MAX_PES_HEADER_SIZE];
uint8_t *buffer;
+ SLConfigDescr sl;
} PESContext;
extern AVInputFormat ff_mpegts_demuxer;
@@ -658,6 +660,83 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt)
pes->flags = 0;
}
+static uint64_t get_bits64(GetBitContext *gb, int bits)
+{
+ uint64_t ret = 0;
+ while (bits > 17) {
+ ret <<= 17;
+ ret |= get_bits(gb, 17);
+ bits -= 17;
+ }
+ ret <<= bits;
+ ret |= get_bits(gb, bits);
+ return ret;
+}
+
+static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf, int buf_size)
+{
+ GetBitContext gb;
+ int au_start_flag = 0, au_end_flag = 0, ocr_flag = 0, idle_flag = 0;
+ int padding_flag = 0, padding_bits = 0, inst_bitrate_flag = 0;
+ int dts_flag = -1, cts_flag = -1;
+ int64_t dts = AV_NOPTS_VALUE, cts = AV_NOPTS_VALUE;
+ init_get_bits(&gb, buf, buf_size*8);
+
+ if (sl->use_au_start)
+ au_start_flag = get_bits1(&gb);
+ if (sl->use_au_end)
+ au_end_flag = get_bits1(&gb);
+ if (!sl->use_au_start && !sl->use_au_end)
+ au_start_flag = au_end_flag = 1;
+ if (sl->ocr_len > 0)
+ ocr_flag = get_bits1(&gb);
+ if (sl->use_idle)
+ idle_flag = get_bits1(&gb);
+ if (sl->use_padding)
+ padding_flag = get_bits1(&gb);
+ if (padding_flag)
+ padding_bits = get_bits(&gb, 3);
+
+ if (!idle_flag && (!padding_flag || padding_bits != 0)) {
+ if (sl->packet_seq_num_len)
+ skip_bits_long(&gb, sl->packet_seq_num_len);
+ if (sl->degr_prior_len)
+ if (get_bits1(&gb))
+ skip_bits(&gb, sl->degr_prior_len);
+ if (ocr_flag)
+ skip_bits_long(&gb, sl->ocr_len);
+ if (au_start_flag) {
+ if (sl->use_rand_acc_pt)
+ get_bits1(&gb);
+ if (sl->au_seq_num_len > 0)
+ skip_bits_long(&gb, sl->au_seq_num_len);
+ if (sl->use_timestamps) {
+ dts_flag = get_bits1(&gb);
+ cts_flag = get_bits1(&gb);
+ }
+ }
+ if (sl->inst_bitrate_len)
+ inst_bitrate_flag = get_bits1(&gb);
+ if (dts_flag == 1)
+ dts = get_bits64(&gb, sl->timestamp_len);
+ if (cts_flag == 1)
+ cts = get_bits64(&gb, sl->timestamp_len);
+ if (sl->au_len > 0)
+ skip_bits_long(&gb, sl->au_len);
+ if (inst_bitrate_flag)
+ skip_bits_long(&gb, sl->inst_bitrate_len);
+ }
+
+ if (dts != AV_NOPTS_VALUE)
+ pes->dts = dts;
+ if (cts != AV_NOPTS_VALUE)
+ pes->pts = cts;
+
+ av_set_pts_info(pes->st, sl->timestamp_len, 1, sl->timestamp_res);
+
+ return (get_bits_count(&gb) + 7) >> 3;
+}
+
/* return non zero if a packet could be constructed */
static int mpegts_push_data(MpegTSFilter *filter,
const uint8_t *buf, int buf_size, int is_start,
@@ -809,6 +888,12 @@ static int mpegts_push_data(MpegTSFilter *filter,
/* we got the full header. We parse it and get the payload */
pes->state = MPEGTS_PAYLOAD;
pes->data_index = 0;
+ if (pes->stream_type == 0x12) {
+ int sl_header_bytes = read_sl_header(pes, &pes->sl, p, buf_size);
+ pes->pes_header_size += sl_header_bytes;
+ p += sl_header_bytes;
+ buf_size -= sl_header_bytes;
+ }
}
break;
case MPEGTS_PAYLOAD:
@@ -962,7 +1047,9 @@ static int parse_MP4ESDescrTag(MP4DescrParseContext *d, int64_t off, int len)
d->active_descr->es_id = es_id;
update_offsets(&d->pb, &off, &len);
parse_mp4_descr(d, off, len, MP4DecConfigDescrTag);
- //SLConfigDescriptor
+ update_offsets(&d->pb, &off, &len);
+ if (len > 0)
+ parse_mp4_descr(d, off, len, MP4SLDescrTag);
d->active_descr = NULL;
return 0;
}
@@ -980,6 +1067,39 @@ static int parse_MP4DecConfigDescrTag(MP4DescrParseContext *d, int64_t off, int
return 0;
}
+static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len)
+{
+ Mp4Descr *descr = d->active_descr;
+ int predefined;
+ if (!descr)
+ return -1;
+
+ predefined = avio_r8(&d->pb);
+ if (!predefined) {
+ int lengths;
+ int flags = avio_r8(&d->pb);
+ descr->sl.use_au_start = !!(flags & 0x80);
+ descr->sl.use_au_end = !!(flags & 0x40);
+ descr->sl.use_rand_acc_pt = !!(flags & 0x20);
+ descr->sl.use_padding = !!(flags & 0x08);
+ descr->sl.use_timestamps = !!(flags & 0x04);
+ descr->sl.use_idle = !!(flags & 0x02);
+ descr->sl.timestamp_res = avio_rb32(&d->pb);
+ avio_rb32(&d->pb);
+ descr->sl.timestamp_len = avio_r8(&d->pb);
+ descr->sl.ocr_len = avio_r8(&d->pb);
+ descr->sl.au_len = avio_r8(&d->pb);
+ descr->sl.inst_bitrate_len = avio_r8(&d->pb);
+ lengths = avio_rb16(&d->pb);
+ descr->sl.degr_prior_len = lengths >> 12;
+ descr->sl.au_seq_num_len = (lengths >> 7) & 0x1f;
+ descr->sl.packet_seq_num_len = (lengths >> 2) & 0x1f;
+ } else {
+ av_log_missing_feature(d->s, "Predefined SLConfigDescriptor\n", 0);
+ }
+ return 0;
+}
+
static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len,
int target_tag) {
int tag;
@@ -1013,6 +1133,9 @@ static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len,
case MP4DecConfigDescrTag:
parse_MP4DecConfigDescrTag(d, off, len1);
break;
+ case MP4SLDescrTag:
+ parse_MP4SLDescrTag(d, off, len1);
+ break;
}
done:
@@ -1047,12 +1170,23 @@ static int mp4_read_od(AVFormatContext *s, const uint8_t *buf, unsigned size,
return 0;
}
-static void SL_packet(AVFormatContext *s, MpegTSContext *ts, const uint8_t *p, const uint8_t *p_end)
+static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
+ MpegTSContext *ts = filter->u.section_filter.opaque;
+ SectionHeader h;
+ const uint8_t *p, *p_end;
AVIOContext pb;
Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = {{ 0 }};
int mp4_descr_count = 0;
int i, pid;
+ AVFormatContext *s = ts->stream;
+
+ p_end = section + section_len - 4;
+ p = section;
+ if (parse_section_header(&h, &p, p_end) < 0)
+ return;
+ if (h.tid != M4OD_TID)
+ return;
mp4_read_od(s, p, (unsigned)(p_end - p), mp4_descr, &mp4_descr_count, MAX_MP4_DESCR_COUNT);
@@ -1074,6 +1208,8 @@ static void SL_packet(AVFormatContext *s, MpegTSContext *ts, const uint8_t *p, c
continue;
}
+ pes->sl = mp4_descr[i].sl;
+
ffio_init_context(&pb, mp4_descr[i].dec_config_descr,
mp4_descr[i].dec_config_descr_len, 0, NULL, NULL, NULL, NULL);
ff_mp4_read_dec_config_descr(s, st, &pb);
@@ -1098,25 +1234,6 @@ static void SL_packet(AVFormatContext *s, MpegTSContext *ts, const uint8_t *p, c
av_free(mp4_descr[i].dec_config_descr);
}
-static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
-{
- MpegTSContext *ts = filter->u.section_filter.opaque;
- SectionHeader h1, *h = &h1;
- const uint8_t *p, *p_end;
-
- av_dlog(ts->stream, "m4SL/od:\n");
- hex_dump_debug(ts->stream, (uint8_t *)section, section_len);
-
- p_end = section + section_len - 4;
- p = section;
- if (parse_section_header(h, &p, p_end) < 0)
- return;
- if (h->tid != M4OD_TID)
- return;
-
- SL_packet(ts->stream, ts, p, p_end);
-}
-
int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type,
const uint8_t **pp, const uint8_t *desc_list_end,
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,