#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
case MKTAG(0xa9,'d','a','y'): key = "date"; break;
case MKTAG(0xa9,'g','e','n'): key = "genre"; break;
case MKTAG(0xa9,'t','o','o'):
+ case MKTAG(0xa9,'s','w','r'): key = "encoder"; break;
case MKTAG(0xa9,'e','n','c'): key = "encoder"; break;
case MKTAG( 'd','e','s','c'): key = "description";break;
case MKTAG( 'l','d','e','s'): key = "synopsis"; break;
static int mov_read_chpl(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
int64_t start;
- int i, nb_chapters, str_len;
+ int i, nb_chapters, str_len, version;
char str[256+1];
if ((atom.size -= 5) < 0)
return 0;
- get_be32(pb); // version + flags
- get_be32(pb); // ???
+ version = get_byte(pb);
+ get_be24(pb);
+ if (version)
+ get_be32(pb); // ???
nb_chapters = get_byte(pb);
for (i = 0; i < nb_chapters; i++) {
uint32_t size = get_be32(pb);
int64_t next = url_ftell(pb) + size - 4;
+ if (size < 12)
+ return -1;
+
dref->type = get_le32(pb);
get_be32(pb); // version + flags
dprintf(c->fc, "type %.4s size %d\n", (char*)&dref->type, size);
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;
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;
- 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;
}
return ff_mov_read_esds(c->fc, pb, atom);
}
+static int mov_read_dac3(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ int ac3info, acmod, lfeon;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+
+ ac3info = get_be24(pb);
+ acmod = (ac3info >> 11) & 0x7;
+ lfeon = (ac3info >> 10) & 0x1;
+ st->codec->channels = ((int[]){2,1,2,3,3,4,4,5})[acmod] + lfeon;
+
+ return 0;
+}
+
static int mov_read_pasp(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
const int num = get_be32(pb);
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
- if (den != 0) {
- if ((st->sample_aspect_ratio.den != 1 || st->sample_aspect_ratio.num) && // default
- (den != st->sample_aspect_ratio.den || num != st->sample_aspect_ratio.num))
- av_log(c->fc, AV_LOG_WARNING,
- "sample aspect ratio already set to %d:%d, overriding by 'pasp' atom\n",
- st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
+ if ((st->sample_aspect_ratio.den != 1 || st->sample_aspect_ratio.num) && // default
+ (den != st->sample_aspect_ratio.den || num != st->sample_aspect_ratio.num)) {
+ av_log(c->fc, AV_LOG_WARNING,
+ "sample aspect ratio already set to %d:%d, ignoring 'pasp' atom (%d:%d)\n",
+ st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
+ num, den);
+ } else if (den != 0) {
st->sample_aspect_ratio.num = num;
st->sample_aspect_ratio.den = den;
}
return mov_read_default(c, pb, atom);
}
+static void mov_metadata_creation_time(AVMetadata **metadata, time_t time)
+{
+ char buffer[32];
+ if (time) {
+ time -= 2082844800; /* seconds between 1904-01-01 and Epoch */
+ strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", gmtime(&time));
+ av_metadata_set2(metadata, "creation_time", buffer, 0);
+ }
+}
+
static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
AVStream *st;
int version;
char language[4] = {0};
unsigned lang;
+ time_t creation_time;
if (c->fc->nb_streams < 1)
return 0;
get_be24(pb); /* flags */
if (version == 1) {
- get_be64(pb);
+ creation_time = get_be64(pb);
get_be64(pb);
} else {
- get_be32(pb); /* creation time */
+ creation_time = get_be32(pb);
get_be32(pb); /* modification time */
}
+ mov_metadata_creation_time(&st->metadata, creation_time);
sc->time_scale = get_be32(pb);
st->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */
static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
+ time_t creation_time;
int version = get_byte(pb); /* version */
get_be24(pb); /* flags */
if (version == 1) {
- get_be64(pb);
+ creation_time = get_be64(pb);
get_be64(pb);
} else {
- get_be32(pb); /* creation time */
+ creation_time = get_be32(pb);
get_be32(pb); /* modification time */
}
+ mov_metadata_creation_time(&c->fc->metadata, creation_time);
c->time_scale = get_be32(pb); /* time scale */
dprintf(c->fc, "time scale = %i\n", c->time_scale);
return CODEC_ID_NONE;
}
-static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
+int ff_mov_read_stsd_entries(MOVContext *c, ByteIOContext *pb, int entries)
{
AVStream *st;
MOVStreamContext *sc;
- int j, entries, pseudo_stream_id;
+ int j, pseudo_stream_id;
if (c->fc->nb_streams < 1)
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
sc = st->priv_data;
- get_byte(pb); /* version */
- get_be24(pb); /* flags */
-
- entries = get_be32(pb);
-
for(pseudo_stream_id=0; pseudo_stream_id<entries; pseudo_stream_id++) {
//Parsing Sample description table
enum CodecID id;
/* Multiple fourcc, we skip JPEG. This is not correct, we should
* export it as a separate AVStream but this needs a few changes
* in the MOV demuxer, patch welcome. */
+ multiple_stsd:
av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n");
url_fskip(pb, size - (url_ftell(pb) - start_pos));
continue;
}
+ /* we cannot demux concatenated h264 streams because of different extradata */
+ if (st->codec->codec_tag && st->codec->codec_tag == AV_RL32("avc1"))
+ goto multiple_stsd;
sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id;
sc->dref_id= dref_id;
st->codec->codec_tag = format;
id = ff_codec_get_id(codec_movaudio_tags, format);
if (id<=0 && ((format&0xFFFF) == 'm'+('s'<<8) || (format&0xFFFF) == 'T'+('S'<<8)))
- id = ff_codec_get_id(ff_codec_wav_tags, bswap_32(format)&0xFFFF);
+ id = ff_codec_get_id(ff_codec_wav_tags, av_bswap32(format)&0xFFFF);
if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO && id > 0) {
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
if (st->codec->extradata_size == 36) {
st->codec->frame_size = AV_RB32(st->codec->extradata+12);
st->codec->channels = AV_RB8 (st->codec->extradata+21);
+ st->codec->sample_rate = AV_RB32(st->codec->extradata+32);
}
break;
default:
return 0;
}
+static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
+{
+ int entries;
+
+ get_byte(pb); /* version */
+ get_be24(pb); /* flags */
+ entries = get_be32(pb);
+
+ return ff_mov_read_stsd_entries(c, pb, entries);
+}
+
static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
AVStream *st;
{ MKTAG('u','d','t','a'), mov_read_default },
{ MKTAG('w','a','v','e'), mov_read_wave },
{ MKTAG('e','s','d','s'), mov_read_esds },
+{ MKTAG('d','a','c','3'), mov_read_dac3 }, /* AC-3 info */
{ MKTAG('w','i','d','e'), mov_read_wide }, /* place holder */
{ MKTAG('c','m','o','v'), mov_read_cmov },
{ 0, NULL }
sample = av_index_search_timestamp(st, timestamp, flags);
dprintf(s, "stream %d, timestamp %"PRId64", sample %d\n", st->index, timestamp, sample);
+ if (sample < 0 && st->nb_index_entries && timestamp < st->index_entries[0].timestamp)
+ sample = 0;
if (sample < 0) /* not sure what to do */
return -1;
sc->current_sample = sample;