MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate; MP4::Atom *moov = atoms->find("moov"); if(!moov) { debug("MP4: Atom 'moov' not found"); return; } MP4::Atom *trak = 0; ByteVector data; MP4::AtomList trakList = moov->findall("trak"); for (unsigned int i = 0; i < trakList.size(); i++) { trak = trakList[i]; MP4::Atom *hdlr = trak->find("mdia", "hdlr"); if(!hdlr) { debug("MP4: Atom 'trak.mdia.hdlr' not found"); return; } file->seek(hdlr->offset); data = file->readBlock(hdlr->length); if(data.mid(16, 4) == "soun") { break; } trak = 0; } if (!trak) { debug("MP4: No audio tracks"); return; } MP4::Atom *mdhd = trak->find("mdia", "mdhd"); if(!mdhd) { debug("MP4: Atom 'trak.mdia.mdhd' not found"); return; } file->seek(mdhd->offset); data = file->readBlock(mdhd->length); uint version = data[8]; if(version == 1) { if (data.size() < 36 + 8) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } const long long unit = data.toLongLong(28U); const long long length = data.toLongLong(36U); d->length = unit ? int(length / unit) : 0; } else { if (data.size() < 24 + 4) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } const unsigned int unit = data.toUInt(20U); const unsigned int length = data.toUInt(24U); d->length = unit ? length / unit : 0; } MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd"); if(!atom) { return; } file->seek(atom->offset); data = file->readBlock(atom->length); if(data.mid(20, 4) == "mp4a") { d->channels = data.toShort(40U); d->bitsPerSample = data.toShort(42U); d->sampleRate = data.toUInt(46U); if(data.mid(56, 4) == "esds" && data[64] == 0x03) { uint pos = 65; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } pos += 4; if(data[pos] == 0x04) { pos += 1; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } pos += 10; d->bitrate = (data.toUInt(pos) + 500) / 1000; } } } else if (data.mid(20, 4) == "alac") { if (atom->length == 88 && data.mid(56, 4) == "alac") { d->bitsPerSample = data.at(69); d->channels = data.at(73); d->bitrate = data.toUInt(80U) / 1000; d->sampleRate = data.toUInt(84U); } } MP4::Atom *drms = atom->find("drms"); if(drms) { d->encrypted = true; } }
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) : AudioProperties(style) { d = new PropertiesPrivate; MP4::Atom *moov = atoms->find("moov"); if(!moov) { debug("MP4: Atom 'moov' not found"); return; } MP4::Atom *trak = 0; ByteVector data; MP4::AtomList trakList = moov->findall("trak"); for (unsigned int i = 0; i < trakList.size(); i++) { trak = trakList[i]; MP4::Atom *hdlr = trak->find("mdia", "hdlr"); if(!hdlr) { debug("MP4: Atom 'trak.mdia.hdlr' not found"); return; } file->seek(hdlr->offset); data = file->readBlock(hdlr->length); if(data.mid(16, 4) == "soun") { break; } trak = 0; } if (!trak) { debug("MP4: No audio tracks"); return; } MP4::Atom *mdhd = trak->find("mdia", "mdhd"); if(!mdhd) { debug("MP4: Atom 'trak.mdia.mdhd' not found"); return; } file->seek(mdhd->offset); data = file->readBlock(mdhd->length); if(data[8] == 0) { unsigned int unit = data.mid(20, 4).toUInt(); unsigned int length = data.mid(24, 4).toUInt(); if (unit == 0) { debug("MP4: No valid data"); d->length = 0; } else { d->length = length / unit; } } else { long long unit = data.mid(28, 8).toLongLong(); long long length = data.mid(36, 8).toLongLong(); if (unit == 0) { debug("MP4: No valid data"); d->length = 0; } else { d->length = int(length / unit); } } MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd"); if(!atom) { return; } file->seek(atom->offset); data = file->readBlock(atom->length); if(data.mid(20, 4) == "mp4a") { d->channels = data.mid(40, 2).toShort(); d->bitsPerSample = data.mid(42, 2).toShort(); d->sampleRate = data.mid(46, 4).toUInt(); if(data.mid(56, 4) == "esds" && data[64] == 0x03) { long pos = 65; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } pos += 4; if(data[pos] == 0x04) { pos += 1; if(data.mid(pos, 3) == "\x80\x80\x80") { pos += 3; } pos += 10; d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000; } } } }
void MP4::Properties::read(File *file, Atoms *atoms) { MP4::Atom *moov = atoms->find("moov"); if(!moov) { debug("MP4: Atom 'moov' not found"); return; } MP4::Atom *trak = 0; ByteVector data; const MP4::AtomList trakList = moov->findall("trak"); for(MP4::AtomList::ConstIterator it = trakList.begin(); it != trakList.end(); ++it) { trak = *it; MP4::Atom *hdlr = trak->find("mdia", "hdlr"); if(!hdlr) { debug("MP4: Atom 'trak.mdia.hdlr' not found"); return; } file->seek(hdlr->offset); data = file->readBlock(hdlr->length); if(data.containsAt("soun", 16)) { break; } trak = 0; } if(!trak) { debug("MP4: No audio tracks"); return; } MP4::Atom *mdhd = trak->find("mdia", "mdhd"); if(!mdhd) { debug("MP4: Atom 'trak.mdia.mdhd' not found"); return; } file->seek(mdhd->offset); data = file->readBlock(mdhd->length); const unsigned int version = data[8]; long long unit; long long length; if(version == 1) { if(data.size() < 36 + 8) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } unit = data.toUInt(28U); length = data.toLongLong(32U); } else { if(data.size() < 24 + 8) { debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); return; } unit = data.toUInt(20U); length = data.toUInt(24U); } if(unit > 0 && length > 0) d->length = static_cast<int>(length * 1000.0 / unit + 0.5); MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd"); if(!atom) { return; } file->seek(atom->offset); data = file->readBlock(atom->length); if(data.containsAt("mp4a", 20)) { d->codec = AAC; d->channels = data.toShort(40U); d->bitsPerSample = data.toShort(42U); d->sampleRate = data.toUInt(46U); if(data.containsAt("esds", 56) && data[64] == 0x03) { unsigned int pos = 65; if(data.containsAt("\x80\x80\x80", pos)) { pos += 3; } pos += 4; if(data[pos] == 0x04) { pos += 1; if(data.containsAt("\x80\x80\x80", pos)) { pos += 3; } pos += 10; d->bitrate = static_cast<int>((data.toUInt(pos) + 500) / 1000.0 + 0.5); } } } else if(data.containsAt("alac", 20)) { if(atom->length == 88 && data.containsAt("alac", 56)) { d->codec = ALAC; d->bitsPerSample = data.at(69); d->channels = data.at(73); d->bitrate = static_cast<int>(data.toUInt(80U) / 1000.0 + 0.5); d->sampleRate = data.toUInt(84U); } } MP4::Atom *drms = atom->find("drms"); if(drms) { d->encrypted = true; } }