diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index bbb00d3538..01b69a70c2 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -893,16 +893,101 @@ static int mp4_read_iods(AVFormatContext *s, const uint8_t *buf, unsigned size, return 0; } +int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type, + const uint8_t **pp, const uint8_t *desc_list_end, + int mp4_dec_config_descr_len, int mp4_es_id, int pid, + uint8_t *mp4_dec_config_descr) +{ + const uint8_t *desc_end; + int desc_len, desc_tag; + char language[4]; + + desc_tag = get8(pp, desc_list_end); + if (desc_tag < 0) + return -1; + desc_len = get8(pp, desc_list_end); + if (desc_len < 0) + return -1; + desc_end = *pp + desc_len; + if (desc_end > desc_list_end) + return -1; + + dprintf(fc, "tag: 0x%02x len=%d\n", desc_tag, desc_len); + + if (st->codec->codec_id == CODEC_ID_NONE && + stream_type == STREAM_TYPE_PRIVATE_DATA) + mpegts_find_stream_type(st, desc_tag, DESC_types); + + switch(desc_tag) { + case 0x1F: /* FMC descriptor */ + get16(pp, desc_end); + if (st->codec->codec_id == CODEC_ID_AAC_LATM && + mp4_dec_config_descr_len && mp4_es_id == pid) { + ByteIOContext pb; + init_put_byte(&pb, mp4_dec_config_descr, + mp4_dec_config_descr_len, 0, NULL, NULL, NULL, NULL); + ff_mp4_read_dec_config_descr(fc, st, &pb); + if (st->codec->codec_id == CODEC_ID_AAC && + st->codec->extradata_size > 0) + st->need_parsing = 0; + } + break; + case 0x56: /* DVB teletext descriptor */ + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + av_metadata_set2(&st->metadata, "language", language, 0); + break; + case 0x59: /* subtitling descriptor */ + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + get8(pp, desc_end); + if (st->codec->extradata) { + if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, *pp, 4)) + av_log_ask_for_sample(fc, "DVB sub with multiple IDs\n"); + } else { + st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE); + if (st->codec->extradata) { + st->codec->extradata_size = 4; + memcpy(st->codec->extradata, *pp, 4); + } + } + *pp += 4; + av_metadata_set2(&st->metadata, "language", language, 0); + break; + case 0x0a: /* ISO 639 language descriptor */ + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + av_metadata_set2(&st->metadata, "language", language, 0); + break; + case 0x05: /* registration descriptor */ + st->codec->codec_tag = bytestream_get_le32(pp); + dprintf(fc, "reg_desc=%.4s\n", (char*)&st->codec->codec_tag); + if (st->codec->codec_id == CODEC_ID_NONE && + stream_type == STREAM_TYPE_PRIVATE_DATA) + mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types); + break; + default: + break; + } + *pp = desc_end; + return 0; +} + static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { MpegTSContext *ts = filter->u.section_filter.opaque; SectionHeader h1, *h = &h1; PESContext *pes; AVStream *st; - const uint8_t *p, *p_end, *desc_list_end, *desc_end; + const uint8_t *p, *p_end, *desc_list_end; int program_info_length, pcr_pid, pid, stream_type; - int desc_list_len, desc_len, desc_tag; - char language[4]; + int desc_list_len; uint32_t prog_reg_desc = 0; /* registration descriptor */ uint8_t *mp4_dec_config_descr = NULL; int mp4_dec_config_descr_len = 0; @@ -1005,81 +1090,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (desc_list_end > p_end) break; for(;;) { - desc_tag = get8(&p, desc_list_end); - if (desc_tag < 0) + if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, desc_list_end, + mp4_dec_config_descr_len, mp4_es_id, pid, mp4_dec_config_descr) < 0) break; - desc_len = get8(&p, desc_list_end); - if (desc_len < 0) - break; - desc_end = p + desc_len; - if (desc_end > desc_list_end) - break; - - dprintf(ts->stream, "tag: 0x%02x len=%d\n", - desc_tag, desc_len); - - if (st->codec->codec_id == CODEC_ID_NONE && - stream_type == STREAM_TYPE_PRIVATE_DATA) - mpegts_find_stream_type(st, desc_tag, DESC_types); - - switch(desc_tag) { - case 0x1F: /* FMC descriptor */ - get16(&p, desc_end); - if (st->codec->codec_id == CODEC_ID_AAC_LATM && - mp4_dec_config_descr_len && mp4_es_id == pid) { - ByteIOContext pb; - init_put_byte(&pb, mp4_dec_config_descr, - mp4_dec_config_descr_len, 0, NULL, NULL, NULL, NULL); - ff_mp4_read_dec_config_descr(ts->stream, st, &pb); - if (st->codec->codec_id == CODEC_ID_AAC && - st->codec->extradata_size > 0) - st->need_parsing = 0; - } - break; - case 0x56: /* DVB teletext descriptor */ - language[0] = get8(&p, desc_end); - language[1] = get8(&p, desc_end); - language[2] = get8(&p, desc_end); - language[3] = 0; - av_metadata_set2(&st->metadata, "language", language, 0); - break; - case 0x59: /* subtitling descriptor */ - language[0] = get8(&p, desc_end); - language[1] = get8(&p, desc_end); - language[2] = get8(&p, desc_end); - language[3] = 0; - get8(&p, desc_end); - if (st->codec->extradata) { - if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, p, 4)) - av_log_ask_for_sample(ts->stream, "DVB sub with multiple IDs\n"); - } else { - st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE); - if (st->codec->extradata) { - st->codec->extradata_size = 4; - memcpy(st->codec->extradata, p, 4); - } - } - p += 4; - av_metadata_set2(&st->metadata, "language", language, 0); - break; - case 0x0a: /* ISO 639 language descriptor */ - language[0] = get8(&p, desc_end); - language[1] = get8(&p, desc_end); - language[2] = get8(&p, desc_end); - language[3] = 0; - av_metadata_set2(&st->metadata, "language", language, 0); - break; - case 0x05: /* registration descriptor */ - st->codec->codec_tag = bytestream_get_le32(&p); - dprintf(ts->stream, "reg_desc=%.4s\n", (char*)&st->codec->codec_tag); - if (st->codec->codec_id == CODEC_ID_NONE && - stream_type == STREAM_TYPE_PRIVATE_DATA) - mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types); - break; - default: - break; - } - p = desc_end; if (prog_reg_desc == AV_RL32("HDMV") && stream_type == 0x83 && pes->sub_st) { ff_program_add_stream_index(ts->stream, h->id, pes->sub_st->index); diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h index 6be9b73f06..25f21079c6 100644 --- a/libavformat/mpegts.h +++ b/libavformat/mpegts.h @@ -63,4 +63,22 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, const uint8_t *buf, int len); void ff_mpegts_parse_close(MpegTSContext *ts); +/** + * Parse an MPEG-2 descriptor + * @param[in] fc Format context (used for logging only) + * @param st Stream + * @param stream_type STREAM_TYPE_xxx + * @param pp Descriptor buffer pointer + * @param desc_list_end End of buffer + * @param mp4_dec_config_descr_len Length of 'mp4_dec_config_descr', or zero if not present + * @param mp4_es_id + * @param pid + * @param mp4_dec_config_descr + * @return <0 to stop processing + */ +int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type, + const uint8_t **pp, const uint8_t *desc_list_end, + int mp4_dec_config_descr_len, int mp4_es_id, int pid, + uint8_t *mp4_dec_config_descr); + #endif /* AVFORMAT_MPEGTS_H */