mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
mpegts: MP4 SL support
This commit is contained in:
parent
c530267024
commit
ca65932bbf
@ -153,6 +153,7 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id);
|
||||
#define MP4ESDescrTag 0x03
|
||||
#define MP4DecConfigDescrTag 0x04
|
||||
#define MP4DecSpecificDescrTag 0x05
|
||||
#define MP4SLDescrTag 0x06
|
||||
|
||||
int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb, MOVAtom atom);
|
||||
enum CodecID ff_mov_get_lpcm_codec_id(int bps, int flags);
|
||||
|
@ -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,
|
||||
|
@ -65,10 +65,28 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
|
||||
const uint8_t *buf, int len);
|
||||
void ff_mpegts_parse_close(MpegTSContext *ts);
|
||||
|
||||
typedef struct {
|
||||
int use_au_start;
|
||||
int use_au_end;
|
||||
int use_rand_acc_pt;
|
||||
int use_padding;
|
||||
int use_timestamps;
|
||||
int use_idle;
|
||||
int timestamp_res;
|
||||
int timestamp_len;
|
||||
int ocr_len;
|
||||
int au_len;
|
||||
int inst_bitrate_len;
|
||||
int degr_prior_len;
|
||||
int au_seq_num_len;
|
||||
int packet_seq_num_len;
|
||||
} SLConfigDescr;
|
||||
|
||||
typedef struct {
|
||||
int es_id;
|
||||
int dec_config_descr_len;
|
||||
uint8_t *dec_config_descr;
|
||||
SLConfigDescr sl;
|
||||
} Mp4Descr;
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user