Originally committed as revision 25806 to svn://svn.ffmpeg.org/ffmpeg/trunktags/n0.8
@@ -138,7 +138,7 @@ OBJS-$(CONFIG_MPEG2SVCD_MUXER) += mpegenc.o | |||
OBJS-$(CONFIG_MPEG1VIDEO_MUXER) += rawenc.o | |||
OBJS-$(CONFIG_MPEG2VIDEO_MUXER) += rawenc.o | |||
OBJS-$(CONFIG_MPEGPS_DEMUXER) += mpeg.o | |||
OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o | |||
OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o isom.o | |||
OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o adtsenc.o | |||
OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += mpegvideodec.o rawdec.o | |||
OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o | |||
@@ -21,9 +21,14 @@ | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
*/ | |||
//#define DEBUG | |||
#include "avformat.h" | |||
#include "internal.h" | |||
#include "isom.h" | |||
#include "riff.h" | |||
#include "libavcodec/mpeg4audio.h" | |||
#include "libavcodec/mpegaudiodata.h" | |||
/* http://www.mp4ra.org */ | |||
/* ordered by muxing preference */ | |||
@@ -326,3 +331,79 @@ int ff_mov_lang_to_iso639(unsigned code, char to[4]) | |||
memcpy(to, mov_mdhd_language_map[code], 4); | |||
return 1; | |||
} | |||
int ff_mp4_read_descr_len(ByteIOContext *pb) | |||
{ | |||
int len = 0; | |||
int count = 4; | |||
while (count--) { | |||
int c = get_byte(pb); | |||
len = (len << 7) | (c & 0x7f); | |||
if (!(c & 0x80)) | |||
break; | |||
} | |||
return len; | |||
} | |||
int ff_mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag) | |||
{ | |||
int len; | |||
*tag = get_byte(pb); | |||
len = ff_mp4_read_descr_len(pb); | |||
dprintf(fc, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); | |||
return len; | |||
} | |||
static const AVCodecTag mp4_audio_types[] = { | |||
{ CODEC_ID_MP3ON4, AOT_PS }, /* old mp3on4 draft */ | |||
{ CODEC_ID_MP3ON4, AOT_L1 }, /* layer 1 */ | |||
{ CODEC_ID_MP3ON4, AOT_L2 }, /* layer 2 */ | |||
{ CODEC_ID_MP3ON4, AOT_L3 }, /* layer 3 */ | |||
{ CODEC_ID_MP4ALS, AOT_ALS }, /* MPEG-4 ALS */ | |||
{ CODEC_ID_NONE, AOT_NULL }, | |||
}; | |||
int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, ByteIOContext *pb) | |||
{ | |||
int len, tag; | |||
int object_type_id = get_byte(pb); | |||
get_byte(pb); /* stream type */ | |||
get_be24(pb); /* buffer size db */ | |||
get_be32(pb); /* max bitrate */ | |||
get_be32(pb); /* avg bitrate */ | |||
st->codec->codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id); | |||
dprintf(fc, "esds object type id 0x%02x\n", object_type_id); | |||
len = ff_mp4_read_descr(fc, pb, &tag); | |||
if (tag == MP4DecSpecificDescrTag) { | |||
dprintf(fc, "Specific MPEG4 header len=%d\n", len); | |||
if((uint64_t)len > (1<<30)) | |||
return -1; | |||
av_free(st->codec->extradata); | |||
st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); | |||
if (!st->codec->extradata) | |||
return AVERROR(ENOMEM); | |||
get_buffer(pb, st->codec->extradata, len); | |||
st->codec->extradata_size = len; | |||
if (st->codec->codec_id == CODEC_ID_AAC) { | |||
MPEG4AudioConfig cfg; | |||
ff_mpeg4audio_get_config(&cfg, st->codec->extradata, | |||
st->codec->extradata_size); | |||
st->codec->channels = cfg.channels; | |||
if (cfg.object_type == 29 && cfg.sampling_index < 3) // old mp3on4 | |||
st->codec->sample_rate = ff_mpa_freq_tab[cfg.sampling_index]; | |||
else if (cfg.ext_sample_rate) | |||
st->codec->sample_rate = cfg.ext_sample_rate; | |||
else | |||
st->codec->sample_rate = cfg.sample_rate; | |||
dprintf(fc, "mp4a config channels %d obj %d ext obj %d " | |||
"sample rate %d ext sample rate %d\n", st->codec->channels, | |||
cfg.object_type, cfg.ext_object_type, | |||
cfg.sample_rate, cfg.ext_sample_rate); | |||
if (!(st->codec->codec_id = ff_codec_get_id(mp4_audio_types, | |||
cfg.object_type))) | |||
st->codec->codec_id = CODEC_ID_AAC; | |||
} | |||
} | |||
return 0; | |||
} |
@@ -142,6 +142,14 @@ typedef struct MOVContext { | |||
} MOVContext; | |||
int ff_mp4_read_descr_len(ByteIOContext *pb); | |||
int ff_mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag); | |||
int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, ByteIOContext *pb); | |||
#define MP4IODescrTag 0x02 | |||
#define MP4ESDescrTag 0x03 | |||
#define MP4DecConfigDescrTag 0x04 | |||
#define MP4DecSpecificDescrTag 0x05 | |||
int ff_mov_read_esds(AVFormatContext *fc, ByteIOContext *pb, MOVAtom atom); | |||
enum CodecID ff_mov_get_lpcm_codec_id(int bps, int flags); | |||
@@ -31,8 +31,6 @@ | |||
#include "avformat.h" | |||
#include "riff.h" | |||
#include "isom.h" | |||
#include "libavcodec/mpeg4audio.h" | |||
#include "libavcodec/mpegaudiodata.h" | |||
#include "libavcodec/get_bits.h" | |||
#if CONFIG_ZLIB | |||
@@ -462,41 +460,6 @@ static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOVAtom atom) | |||
return 0; | |||
} | |||
int ff_mp4_read_descr_len(ByteIOContext *pb) | |||
{ | |||
int len = 0; | |||
int count = 4; | |||
while (count--) { | |||
int c = get_byte(pb); | |||
len = (len << 7) | (c & 0x7f); | |||
if (!(c & 0x80)) | |||
break; | |||
} | |||
return len; | |||
} | |||
static int mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag) | |||
{ | |||
int len; | |||
*tag = get_byte(pb); | |||
len = ff_mp4_read_descr_len(pb); | |||
dprintf(fc, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); | |||
return len; | |||
} | |||
#define MP4ESDescrTag 0x03 | |||
#define MP4DecConfigDescrTag 0x04 | |||
#define MP4DecSpecificDescrTag 0x05 | |||
static const AVCodecTag mp4_audio_types[] = { | |||
{ CODEC_ID_MP3ON4, AOT_PS }, /* old mp3on4 draft */ | |||
{ CODEC_ID_MP3ON4, AOT_L1 }, /* layer 1 */ | |||
{ CODEC_ID_MP3ON4, AOT_L2 }, /* layer 2 */ | |||
{ CODEC_ID_MP3ON4, AOT_L3 }, /* layer 3 */ | |||
{ CODEC_ID_MP4ALS, AOT_ALS }, /* MPEG-4 ALS */ | |||
{ CODEC_ID_NONE, AOT_NULL }, | |||
}; | |||
int ff_mov_read_esds(AVFormatContext *fc, ByteIOContext *pb, MOVAtom atom) | |||
{ | |||
AVStream *st; | |||
@@ -507,55 +470,16 @@ int ff_mov_read_esds(AVFormatContext *fc, ByteIOContext *pb, MOVAtom atom) | |||
st = fc->streams[fc->nb_streams-1]; | |||
get_be32(pb); /* version + flags */ | |||
len = mp4_read_descr(fc, pb, &tag); | |||
len = ff_mp4_read_descr(fc, pb, &tag); | |||
if (tag == MP4ESDescrTag) { | |||
get_be16(pb); /* ID */ | |||
get_byte(pb); /* priority */ | |||
} else | |||
get_be16(pb); /* ID */ | |||
len = mp4_read_descr(fc, pb, &tag); | |||
if (tag == MP4DecConfigDescrTag) { | |||
int object_type_id = get_byte(pb); | |||
get_byte(pb); /* stream type */ | |||
get_be24(pb); /* buffer size db */ | |||
get_be32(pb); /* max bitrate */ | |||
get_be32(pb); /* avg bitrate */ | |||
st->codec->codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id); | |||
dprintf(fc, "esds object type id 0x%02x\n", object_type_id); | |||
len = mp4_read_descr(fc, pb, &tag); | |||
if (tag == MP4DecSpecificDescrTag) { | |||
dprintf(fc, "Specific MPEG4 header len=%d\n", len); | |||
if((uint64_t)len > (1<<30)) | |||
return -1; | |||
av_free(st->codec->extradata); | |||
st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); | |||
if (!st->codec->extradata) | |||
return AVERROR(ENOMEM); | |||
get_buffer(pb, st->codec->extradata, len); | |||
st->codec->extradata_size = len; | |||
if (st->codec->codec_id == CODEC_ID_AAC) { | |||
MPEG4AudioConfig cfg; | |||
ff_mpeg4audio_get_config(&cfg, st->codec->extradata, | |||
st->codec->extradata_size); | |||
st->codec->channels = cfg.channels; | |||
if (cfg.object_type == 29 && cfg.sampling_index < 3) // old mp3on4 | |||
st->codec->sample_rate = ff_mpa_freq_tab[cfg.sampling_index]; | |||
else if (cfg.ext_sample_rate) | |||
st->codec->sample_rate = cfg.ext_sample_rate; | |||
else | |||
st->codec->sample_rate = cfg.sample_rate; | |||
dprintf(fc, "mp4a config channels %d obj %d ext obj %d " | |||
"sample rate %d ext sample rate %d\n", st->codec->channels, | |||
cfg.object_type, cfg.ext_object_type, | |||
cfg.sample_rate, cfg.ext_sample_rate); | |||
if (!(st->codec->codec_id = ff_codec_get_id(mp4_audio_types, | |||
cfg.object_type))) | |||
st->codec->codec_id = CODEC_ID_AAC; | |||
} | |||
} | |||
} | |||
len = ff_mp4_read_descr(fc, pb, &tag); | |||
if (tag == MP4DecConfigDescrTag) | |||
ff_mp4_read_dec_config_descr(fc, st, pb); | |||
return 0; | |||
} | |||
@@ -30,6 +30,7 @@ | |||
#include "mpegts.h" | |||
#include "internal.h" | |||
#include "seek.h" | |||
#include "isom.h" | |||
/* 1.0 second at 24Mbit/s */ | |||
#define MAX_SCAN_PACKETS 32000 | |||
@@ -852,6 +853,42 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid) | |||
return pes; | |||
} | |||
static int mp4_read_iods(AVFormatContext *s, uint8_t *buf, unsigned size, | |||
uint16_t *es_id, uint8_t **dec_config_descr, | |||
int *dec_config_descr_size) | |||
{ | |||
ByteIOContext pb; | |||
int tag; | |||
unsigned len; | |||
init_put_byte(&pb, buf, size, 0, NULL, NULL, NULL, NULL); | |||
len = ff_mp4_read_descr(s, &pb, &tag); | |||
if (tag == MP4IODescrTag) { | |||
get_be16(&pb); // ID | |||
get_byte(&pb); | |||
get_byte(&pb); | |||
get_byte(&pb); | |||
get_byte(&pb); | |||
get_byte(&pb); | |||
len = ff_mp4_read_descr(s, &pb, &tag); | |||
if (tag == MP4ESDescrTag) { | |||
*es_id = get_be16(&pb); /* ES_ID */ | |||
dprintf(s, "ES_ID %#x\n", *es_id); | |||
get_byte(&pb); /* priority */ | |||
len = ff_mp4_read_descr(s, &pb, &tag); | |||
if (tag == MP4DecConfigDescrTag) { | |||
*dec_config_descr = av_malloc(len); | |||
if (!*dec_config_descr) | |||
return AVERROR(ENOMEM); | |||
*dec_config_descr_size = len; | |||
get_buffer(&pb, *dec_config_descr, len); | |||
} | |||
} | |||
} | |||
return 0; | |||
} | |||
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) | |||
{ | |||
MpegTSContext *ts = filter->u.section_filter.opaque; | |||
@@ -863,6 +900,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len | |||
int desc_list_len, desc_len, desc_tag; | |||
char language[4]; | |||
uint32_t prog_reg_desc = 0; /* registration descriptor */ | |||
uint8_t *mp4_dec_config_descr = NULL; | |||
int mp4_dec_config_descr_len = 0; | |||
int mp4_es_id = 0; | |||
#ifdef DEBUG | |||
dprintf(ts->stream, "PMT: len %i\n", section_len); | |||
@@ -895,11 +935,20 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len | |||
uint8_t tag, len; | |||
tag = get8(&p, p_end); | |||
len = get8(&p, p_end); | |||
dprintf(ts->stream, "program tag: 0x%02x len=%d\n", tag, len); | |||
if(len > program_info_length - 2) | |||
//something else is broken, exit the program_descriptors_loop | |||
break; | |||
program_info_length -= len + 2; | |||
if(tag == 0x05 && len >= 4) { // registration descriptor | |||
if (tag == 0x1d) { // IOD descriptor | |||
get8(&p, p_end); // scope | |||
get8(&p, p_end); // label | |||
len -= 2; | |||
mp4_read_iods(ts->stream, p, len, &mp4_es_id, | |||
&mp4_dec_config_descr, &mp4_dec_config_descr_len); | |||
} else if (tag == 0x05 && len >= 4) { // registration descriptor | |||
prog_reg_desc = bytestream_get_le32(&p); | |||
len -= 4; | |||
} | |||
@@ -968,6 +1017,19 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len | |||
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); | |||