|
@@ -28,6 +28,7 @@
|
|
#include "libavutil/mathematics.h"
|
|
#include "libavutil/mathematics.h"
|
|
#include "libavutil/opt.h"
|
|
#include "libavutil/opt.h"
|
|
#include "libavcodec/bytestream.h"
|
|
#include "libavcodec/bytestream.h"
|
|
|
|
+#include "libavcodec/get_bits.h"
|
|
#include "avformat.h"
|
|
#include "avformat.h"
|
|
#include "mpegts.h"
|
|
#include "mpegts.h"
|
|
#include "internal.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 */
|
|
int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */
|
|
uint8_t header[MAX_PES_HEADER_SIZE];
|
|
uint8_t header[MAX_PES_HEADER_SIZE];
|
|
uint8_t *buffer;
|
|
uint8_t *buffer;
|
|
|
|
+ SLConfigDescr sl;
|
|
} PESContext;
|
|
} PESContext;
|
|
|
|
|
|
extern AVInputFormat ff_mpegts_demuxer;
|
|
extern AVInputFormat ff_mpegts_demuxer;
|
|
@@ -658,6 +660,83 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt)
|
|
pes->flags = 0;
|
|
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 */
|
|
/* return non zero if a packet could be constructed */
|
|
static int mpegts_push_data(MpegTSFilter *filter,
|
|
static int mpegts_push_data(MpegTSFilter *filter,
|
|
const uint8_t *buf, int buf_size, int is_start,
|
|
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 */
|
|
/* we got the full header. We parse it and get the payload */
|
|
pes->state = MPEGTS_PAYLOAD;
|
|
pes->state = MPEGTS_PAYLOAD;
|
|
pes->data_index = 0;
|
|
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;
|
|
break;
|
|
case MPEGTS_PAYLOAD:
|
|
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;
|
|
d->active_descr->es_id = es_id;
|
|
update_offsets(&d->pb, &off, &len);
|
|
update_offsets(&d->pb, &off, &len);
|
|
parse_mp4_descr(d, off, len, MP4DecConfigDescrTag);
|
|
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;
|
|
d->active_descr = NULL;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -980,6 +1067,39 @@ static int parse_MP4DecConfigDescrTag(MP4DescrParseContext *d, int64_t off, int
|
|
return 0;
|
|
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,
|
|
static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len,
|
|
int target_tag) {
|
|
int target_tag) {
|
|
int tag;
|
|
int tag;
|
|
@@ -1013,6 +1133,9 @@ static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len,
|
|
case MP4DecConfigDescrTag:
|
|
case MP4DecConfigDescrTag:
|
|
parse_MP4DecConfigDescrTag(d, off, len1);
|
|
parse_MP4DecConfigDescrTag(d, off, len1);
|
|
break;
|
|
break;
|
|
|
|
+ case MP4SLDescrTag:
|
|
|
|
+ parse_MP4SLDescrTag(d, off, len1);
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
|
|
done:
|
|
done:
|
|
@@ -1047,12 +1170,23 @@ static int mp4_read_od(AVFormatContext *s, const uint8_t *buf, unsigned size,
|
|
return 0;
|
|
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;
|
|
AVIOContext pb;
|
|
Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = {{ 0 }};
|
|
Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = {{ 0 }};
|
|
int mp4_descr_count = 0;
|
|
int mp4_descr_count = 0;
|
|
int i, pid;
|
|
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);
|
|
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;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ pes->sl = mp4_descr[i].sl;
|
|
|
|
+
|
|
ffio_init_context(&pb, mp4_descr[i].dec_config_descr,
|
|
ffio_init_context(&pb, mp4_descr[i].dec_config_descr,
|
|
mp4_descr[i].dec_config_descr_len, 0, NULL, NULL, NULL, NULL);
|
|
mp4_descr[i].dec_config_descr_len, 0, NULL, NULL, NULL, NULL);
|
|
ff_mp4_read_dec_config_descr(s, st, &pb);
|
|
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);
|
|
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,
|
|
int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type,
|
|
const uint8_t **pp, const uint8_t *desc_list_end,
|
|
const uint8_t **pp, const uint8_t *desc_list_end,
|
|
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
|
|
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
|