improved handling of unsupported files
additionally: - added detection for QuickTime files - minor adjustments
This commit is contained in:
parent
e0437c0a43
commit
ddf9ef02f8
|
@ -207,8 +207,9 @@ startParsingSignature:
|
||||||
// continue reading signature
|
// continue reading signature
|
||||||
goto startParsingSignature;
|
goto startParsingSignature;
|
||||||
|
|
||||||
case ContainerFormat::Mp4: {
|
case ContainerFormat::Mp4:
|
||||||
// EBML/Matroska is handled using Mp4Container instance
|
case ContainerFormat::QuickTime: {
|
||||||
|
// MP4/QuickTime is handled using Mp4Container instance
|
||||||
m_container = make_unique<Mp4Container>(*this, m_containerOffset);
|
m_container = make_unique<Mp4Container>(*this, m_containerOffset);
|
||||||
NotificationList notifications;
|
NotificationList notifications;
|
||||||
try {
|
try {
|
||||||
|
@ -512,7 +513,7 @@ bool MediaFileInfo::createAppropriateTags(bool treatUnknownFilesAsMp3Files, TagU
|
||||||
// check if tags need to be created/adjusted/removed
|
// check if tags need to be created/adjusted/removed
|
||||||
bool targetsRequired = !requiredTargets.empty() && (requiredTargets.size() != 1 && requiredTargets.front().isEmpty());
|
bool targetsRequired = !requiredTargets.empty() && (requiredTargets.size() != 1 && requiredTargets.front().isEmpty());
|
||||||
bool targetsSupported = false;
|
bool targetsSupported = false;
|
||||||
if(m_container) {
|
if(areTagsSupported() && m_container) {
|
||||||
// container object takes care of tag management
|
// container object takes care of tag management
|
||||||
if(targetsRequired) {
|
if(targetsRequired) {
|
||||||
// check whether container supports targets
|
// check whether container supports targets
|
||||||
|
@ -723,54 +724,17 @@ const char *MediaFileInfo::containerFormatAbbreviation() const
|
||||||
*/
|
*/
|
||||||
const char *MediaFileInfo::mimeType() const
|
const char *MediaFileInfo::mimeType() const
|
||||||
{
|
{
|
||||||
|
MediaType mediaType;
|
||||||
switch(m_containerFormat) {
|
switch(m_containerFormat) {
|
||||||
case ContainerFormat::Asf:
|
|
||||||
return "video/x-ms-asf";
|
|
||||||
case ContainerFormat::Gif87a:
|
|
||||||
case ContainerFormat::Gif89a:
|
|
||||||
return "image/gif";
|
|
||||||
case ContainerFormat::Jpeg:
|
|
||||||
return "image/jpeg";
|
|
||||||
case ContainerFormat::Png:
|
|
||||||
return "image/png";
|
|
||||||
case ContainerFormat::MpegAudioFrames:
|
|
||||||
return "audio/mpeg";
|
|
||||||
case ContainerFormat::Mp4:
|
case ContainerFormat::Mp4:
|
||||||
if(hasTracksOfType(MediaType::Video)) {
|
|
||||||
return "video/mp4";
|
|
||||||
}
|
|
||||||
return "audio/mp4";
|
|
||||||
case ContainerFormat::Ogg:
|
case ContainerFormat::Ogg:
|
||||||
if(hasTracksOfType(MediaType::Video)) {
|
|
||||||
return "video/ogg";
|
|
||||||
}
|
|
||||||
return "audio/ogg";
|
|
||||||
case ContainerFormat::Matroska:
|
case ContainerFormat::Matroska:
|
||||||
if(hasTracksOfType(MediaType::Video)) {
|
mediaType = hasTracksOfType(MediaType::Video) ? MediaType::Video : MediaType::Audio;
|
||||||
return "video/x-matroska";
|
break;
|
||||||
}
|
|
||||||
return "audio/x-matroska";
|
|
||||||
case ContainerFormat::Bzip2:
|
|
||||||
return "application/x-bzip";
|
|
||||||
case ContainerFormat::Gzip:
|
|
||||||
return "application/gzip";
|
|
||||||
case ContainerFormat::Lha:
|
|
||||||
return "application/x-lzh-compressed";
|
|
||||||
case ContainerFormat::Rar:
|
|
||||||
return "application/x-rar-compressed";
|
|
||||||
case ContainerFormat::Lzip:
|
|
||||||
return "application/x-lzip";
|
|
||||||
case ContainerFormat::Zip:
|
|
||||||
return "application/zip";
|
|
||||||
case ContainerFormat::SevenZ:
|
|
||||||
return "application/x-7z-compressed";
|
|
||||||
case ContainerFormat::WindowsBitmap:
|
|
||||||
return "image/bmp";
|
|
||||||
case ContainerFormat::WindowsIcon:
|
|
||||||
return "image/vnd.microsoft.icon";
|
|
||||||
default:
|
default:
|
||||||
return "";
|
mediaType = MediaType::Unknown;
|
||||||
}
|
}
|
||||||
|
return Media::containerMimeType(m_containerFormat, mediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -781,7 +745,7 @@ const char *MediaFileInfo::mimeType() const
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the returned
|
* \remarks The MediaFileInfo keeps the ownership over the returned
|
||||||
* pointers. The returned Tracks will be destroyed when the
|
* pointers. The returned Tracks will be destroyed when the
|
||||||
* MediaFileInfo gets invalidated.
|
* MediaFileInfo is invalidated.
|
||||||
*
|
*
|
||||||
* \sa parseTracks()
|
* \sa parseTracks()
|
||||||
*/
|
*/
|
||||||
|
@ -950,7 +914,7 @@ bool MediaFileInfo::removeAllId3v2Tags()
|
||||||
* \returns Returns the first ID3v2 tag of the current file.
|
* \returns Returns the first ID3v2 tag of the current file.
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the created tag. It will be
|
* \remarks The MediaFileInfo keeps the ownership over the created tag. It will be
|
||||||
* destroyed when the MediaFileInfo gets invalidated.
|
* destroyed when the MediaFileInfo is invalidated.
|
||||||
*
|
*
|
||||||
* \sa applyChanges()
|
* \sa applyChanges()
|
||||||
*/
|
*/
|
||||||
|
@ -1066,9 +1030,6 @@ bool MediaFileInfo::areTracksSupported() const
|
||||||
*/
|
*/
|
||||||
bool MediaFileInfo::areTagsSupported() const
|
bool MediaFileInfo::areTagsSupported() const
|
||||||
{
|
{
|
||||||
if(hasAnyTag()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
switch(m_containerFormat) {
|
switch(m_containerFormat) {
|
||||||
case ContainerFormat::Mp4:
|
case ContainerFormat::Mp4:
|
||||||
case ContainerFormat::MpegAudioFrames:
|
case ContainerFormat::MpegAudioFrames:
|
||||||
|
@ -1076,9 +1037,12 @@ bool MediaFileInfo::areTagsSupported() const
|
||||||
case ContainerFormat::Matroska:
|
case ContainerFormat::Matroska:
|
||||||
case ContainerFormat::Webm:
|
case ContainerFormat::Webm:
|
||||||
case ContainerFormat::Adts:
|
case ContainerFormat::Adts:
|
||||||
|
// these container formats are supported
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
// the container format is unsupported
|
||||||
|
// -> an ID3 tag might be already present, in this case the tags are considered supported
|
||||||
|
return !m_container && (hasId3v1Tag() || hasId3v2Tag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,12 +1051,12 @@ bool MediaFileInfo::areTagsSupported() const
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the returned
|
* \remarks The MediaFileInfo keeps the ownership over the returned
|
||||||
* pointer. The returned MP4 tag will be destroyed when the
|
* pointer. The returned MP4 tag will be destroyed when the
|
||||||
* MediaFileInfo gets invalidated.
|
* MediaFileInfo is invalidated.
|
||||||
*/
|
*/
|
||||||
Mp4Tag *MediaFileInfo::mp4Tag() const
|
Mp4Tag *MediaFileInfo::mp4Tag() const
|
||||||
{
|
{
|
||||||
// simply return the first tag here since MP4 files never contain multiple tags
|
// simply return the first tag here since MP4 files never contain multiple tags
|
||||||
return m_containerFormat == ContainerFormat::Mp4 && m_container && m_container->tagCount() > 0 ? static_cast<Mp4Container *>(m_container.get())->tags().front().get() : nullptr;
|
return (m_containerFormat == ContainerFormat::Mp4 || m_containerFormat == ContainerFormat::QuickTime) && m_container && m_container->tagCount() > 0 ? static_cast<Mp4Container *>(m_container.get())->tags().front().get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1100,7 +1064,7 @@ Mp4Tag *MediaFileInfo::mp4Tag() const
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the returned
|
* \remarks The MediaFileInfo keeps the ownership over the returned
|
||||||
* pointers. The returned Matroska tags will be destroyed when the
|
* pointers. The returned Matroska tags will be destroyed when the
|
||||||
* MediaFileInfo gets invalidated.
|
* MediaFileInfo is invalidated.
|
||||||
*/
|
*/
|
||||||
const vector<unique_ptr<MatroskaTag> > &MediaFileInfo::matroskaTags() const
|
const vector<unique_ptr<MatroskaTag> > &MediaFileInfo::matroskaTags() const
|
||||||
{
|
{
|
||||||
|
@ -1117,7 +1081,7 @@ const vector<unique_ptr<MatroskaTag> > &MediaFileInfo::matroskaTags() const
|
||||||
* \brief Returns all chapters assigned to the current file.
|
* \brief Returns all chapters assigned to the current file.
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the chapters which will be
|
* \remarks The MediaFileInfo keeps the ownership over the chapters which will be
|
||||||
* destroyed when the MediaFileInfo gets invalidated.
|
* destroyed when the MediaFileInfo is invalidated.
|
||||||
*/
|
*/
|
||||||
vector<AbstractChapter *> MediaFileInfo::chapters() const
|
vector<AbstractChapter *> MediaFileInfo::chapters() const
|
||||||
{
|
{
|
||||||
|
@ -1136,7 +1100,7 @@ vector<AbstractChapter *> MediaFileInfo::chapters() const
|
||||||
* \brief Returns all attachments assigned to the current file.
|
* \brief Returns all attachments assigned to the current file.
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the attachments which will be
|
* \remarks The MediaFileInfo keeps the ownership over the attachments which will be
|
||||||
* destroyed when the MediaFileInfo gets invalidated.
|
* destroyed when the MediaFileInfo is invalidated.
|
||||||
*/
|
*/
|
||||||
vector<AbstractAttachment *> MediaFileInfo::attachments() const
|
vector<AbstractAttachment *> MediaFileInfo::attachments() const
|
||||||
{
|
{
|
||||||
|
@ -1318,7 +1282,7 @@ void MediaFileInfo::mergeId3v2Tags()
|
||||||
* Previous elements of the vector will not be cleared.
|
* Previous elements of the vector will not be cleared.
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the tags which will be
|
* \remarks The MediaFileInfo keeps the ownership over the tags which will be
|
||||||
* destroyed when the MediaFileInfo gets invalidated.
|
* destroyed when the MediaFileInfo is invalidated.
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::tags(vector<Tag *> &tags) const
|
void MediaFileInfo::tags(vector<Tag *> &tags) const
|
||||||
{
|
{
|
||||||
|
@ -1338,7 +1302,7 @@ void MediaFileInfo::tags(vector<Tag *> &tags) const
|
||||||
* \brief Returns all tags assigned to the current file.
|
* \brief Returns all tags assigned to the current file.
|
||||||
*
|
*
|
||||||
* \remarks The MediaFileInfo keeps the ownership over the tags which will be
|
* \remarks The MediaFileInfo keeps the ownership over the tags which will be
|
||||||
* destroyed when the MediaFileInfo gets invalidated.
|
* destroyed when the MediaFileInfo is invalidated.
|
||||||
*/
|
*/
|
||||||
vector<Tag *> MediaFileInfo::tags() const
|
vector<Tag *> MediaFileInfo::tags() const
|
||||||
{
|
{
|
||||||
|
@ -1376,7 +1340,7 @@ void MediaFileInfo::makeMp3File()
|
||||||
stream().seekp(-128, ios_base::end);
|
stream().seekp(-128, ios_base::end);
|
||||||
try {
|
try {
|
||||||
m_id3v1Tag->make(stream());
|
m_id3v1Tag->make(stream());
|
||||||
} catch(Failure &) {
|
} catch(const Failure &) {
|
||||||
addNotification(NotificationType::Warning, "Unable to write ID3v1 tag.", context);
|
addNotification(NotificationType::Warning, "Unable to write ID3v1 tag.", context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1400,7 +1364,7 @@ void MediaFileInfo::makeMp3File()
|
||||||
stream().seekp(0, ios_base::end);
|
stream().seekp(0, ios_base::end);
|
||||||
try {
|
try {
|
||||||
m_id3v1Tag->make(stream());
|
m_id3v1Tag->make(stream());
|
||||||
} catch(Failure &) {
|
} catch(const Failure &) {
|
||||||
addNotification(NotificationType::Warning, "Unable to write ID3v1 tag.", context);
|
addNotification(NotificationType::Warning, "Unable to write ID3v1 tag.", context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1515,7 +1479,7 @@ void MediaFileInfo::makeMp3File()
|
||||||
updateStatus("Writing ID3v1 tag ...");
|
updateStatus("Writing ID3v1 tag ...");
|
||||||
try {
|
try {
|
||||||
m_id3v1Tag->make(stream());
|
m_id3v1Tag->make(stream());
|
||||||
} catch(Failure &) {
|
} catch(const Failure &) {
|
||||||
addNotification(NotificationType::Warning, "Unable to write ID3v1 tag.", context);
|
addNotification(NotificationType::Warning, "Unable to write ID3v1 tag.", context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ void Mp4Atom::internalParse()
|
||||||
invalidateStatus();
|
invalidateStatus();
|
||||||
static const string context("parsing MP4 atom");
|
static const string context("parsing MP4 atom");
|
||||||
if(maxTotalSize() < minimumElementSize()) {
|
if(maxTotalSize() < minimumElementSize()) {
|
||||||
addNotification(NotificationType::Critical, "Atom is smaller then 8 byte and hence invalid. The maximum size within the parent atom is " + numberToString(maxTotalSize()) + ".", context);
|
addNotification(NotificationType::Critical, "Atom is smaller then 8 byte and hence invalid. The remaining size within the parent atom is " + numberToString(maxTotalSize()) + ".", context);
|
||||||
throw TruncatedDataException();
|
throw TruncatedDataException();
|
||||||
}
|
}
|
||||||
stream().seekg(startOffset());
|
stream().seekg(startOffset());
|
||||||
|
|
|
@ -57,7 +57,7 @@ void Mp4Container::internalParseHeader()
|
||||||
m_doctype = reader().readString(4);
|
m_doctype = reader().readString(4);
|
||||||
m_version = reader().readUInt32BE();
|
m_version = reader().readUInt32BE();
|
||||||
} else {
|
} else {
|
||||||
m_doctype = "mp41";
|
m_doctype.clear();
|
||||||
m_version = 0;
|
m_version = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,7 @@ void Mp4Tag::parse(Mp4Atom &metaAtom)
|
||||||
Mp4Atom *subAtom = nullptr;
|
Mp4Atom *subAtom = nullptr;
|
||||||
try {
|
try {
|
||||||
metaAtom.childById(Mp4AtomIds::HandlerReference);
|
metaAtom.childById(Mp4AtomIds::HandlerReference);
|
||||||
} catch(Failure &) {
|
} catch(const Failure &) {
|
||||||
addNotification(NotificationType::Critical, "Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
|
addNotification(NotificationType::Critical, "Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
|
||||||
}
|
}
|
||||||
if(subAtom) {
|
if(subAtom) {
|
||||||
|
@ -206,7 +206,7 @@ void Mp4Tag::parse(Mp4Atom &metaAtom)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
subAtom = metaAtom.childById(Mp4AtomIds::ItunesList);
|
subAtom = metaAtom.childById(Mp4AtomIds::ItunesList);
|
||||||
} catch(Failure &) {
|
} catch(const Failure &) {
|
||||||
addNotification(NotificationType::Critical, "Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
|
addNotification(NotificationType::Critical, "Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
|
||||||
}
|
}
|
||||||
if(subAtom) {
|
if(subAtom) {
|
||||||
|
@ -217,7 +217,7 @@ void Mp4Tag::parse(Mp4Atom &metaAtom)
|
||||||
tagField.invalidateNotifications();
|
tagField.invalidateNotifications();
|
||||||
tagField.reparse(*child);
|
tagField.reparse(*child);
|
||||||
fields().insert(pair<fieldType::identifierType, fieldType>(child->id(), tagField));
|
fields().insert(pair<fieldType::identifierType, fieldType>(child->id(), tagField));
|
||||||
} catch(Failure &) {
|
} catch(const Failure &) {
|
||||||
}
|
}
|
||||||
addNotifications(context, *child);
|
addNotifications(context, *child);
|
||||||
addNotifications(context, tagField);
|
addNotifications(context, tagField);
|
||||||
|
|
|
@ -1165,6 +1165,7 @@ void Mp4Track::internalParseHeader()
|
||||||
addNotification(NotificationType::Critical, "\"trak\"-atom is null.", context);
|
addNotification(NotificationType::Critical, "\"trak\"-atom is null.", context);
|
||||||
throw InvalidDataException();
|
throw InvalidDataException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get atoms
|
// get atoms
|
||||||
try {
|
try {
|
||||||
if(!(m_tkhdAtom = m_trakAtom->childById(TrackHeader))) {
|
if(!(m_tkhdAtom = m_trakAtom->childById(TrackHeader))) {
|
||||||
|
@ -1207,11 +1208,13 @@ void Mp4Track::internalParseHeader()
|
||||||
addNotification(NotificationType::Critical, "No \"stsz\"/\"stz2\"-atom found.", context);
|
addNotification(NotificationType::Critical, "No \"stsz\"/\"stz2\"-atom found.", context);
|
||||||
throw InvalidDataException();
|
throw InvalidDataException();
|
||||||
}
|
}
|
||||||
} catch(Failure &) {
|
} catch(const Failure &) {
|
||||||
addNotification(NotificationType::Critical, "Unable to parse relevant atoms.", context);
|
addNotification(NotificationType::Critical, "Unable to parse relevant atoms.", context);
|
||||||
throw InvalidDataException();
|
throw InvalidDataException();
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryReader &reader = m_trakAtom->reader();
|
BinaryReader &reader = m_trakAtom->reader();
|
||||||
|
|
||||||
// read tkhd atom
|
// read tkhd atom
|
||||||
m_istream->seekg(m_tkhdAtom->startOffset() + 8); // seek to beg, skip size and name
|
m_istream->seekg(m_tkhdAtom->startOffset() + 8); // seek to beg, skip size and name
|
||||||
byte atomVersion = reader.readByte(); // read version
|
byte atomVersion = reader.readByte(); // read version
|
||||||
|
@ -1236,8 +1239,9 @@ void Mp4Track::internalParseHeader()
|
||||||
m_modificationTime = DateTime();
|
m_modificationTime = DateTime();
|
||||||
m_id = 0;
|
m_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read mdhd atom
|
// read mdhd atom
|
||||||
m_istream->seekg(m_mdhdAtom->startOffset() + 8); // seek to beg, skip size and name
|
m_istream->seekg(m_mdhdAtom->dataOffset()); // seek to beg, skip size and name
|
||||||
atomVersion = reader.readByte(); // read version
|
atomVersion = reader.readByte(); // read version
|
||||||
m_istream->seekg(3, ios_base::cur); // skip flags
|
m_istream->seekg(3, ios_base::cur); // skip flags
|
||||||
switch(atomVersion) {
|
switch(atomVersion) {
|
||||||
|
@ -1258,12 +1262,17 @@ void Mp4Track::internalParseHeader()
|
||||||
m_timeScale = 0;
|
m_timeScale = 0;
|
||||||
m_duration = TimeSpan();
|
m_duration = TimeSpan();
|
||||||
}
|
}
|
||||||
uint16 rawLanguage = reader.readUInt16BE();
|
uint16 tmp = reader.readUInt16BE();
|
||||||
char buff[3];
|
if(tmp) {
|
||||||
buff[0] = ((rawLanguage & 0x7C00) >> 0xA) + 0x60;
|
char buff[3];
|
||||||
buff[1] = ((rawLanguage & 0x03E0) >> 0x5) + 0x60;
|
buff[0] = ((tmp & 0x7C00) >> 0xA) + 0x60;
|
||||||
buff[2] = ((rawLanguage & 0x001F) >> 0x0) + 0x60;
|
buff[1] = ((tmp & 0x03E0) >> 0x5) + 0x60;
|
||||||
m_language = string(buff, 3);
|
buff[2] = ((tmp & 0x001F) >> 0x0) + 0x60;
|
||||||
|
m_language = string(buff, 3);
|
||||||
|
} else {
|
||||||
|
m_language.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// read hdlr atom
|
// read hdlr atom
|
||||||
// -> seek to begin skipping size, name, version, flags and reserved bytes
|
// -> seek to begin skipping size, name, version, flags and reserved bytes
|
||||||
m_istream->seekg(m_hdlrAtom->dataOffset() + 8);
|
m_istream->seekg(m_hdlrAtom->dataOffset() + 8);
|
||||||
|
@ -1284,19 +1293,26 @@ void Mp4Track::internalParseHeader()
|
||||||
default:
|
default:
|
||||||
m_mediaType = MediaType::Unknown;
|
m_mediaType = MediaType::Unknown;
|
||||||
}
|
}
|
||||||
|
// -> name
|
||||||
// name
|
|
||||||
m_istream->seekg(12, ios_base::cur); // skip reserved bytes
|
m_istream->seekg(12, ios_base::cur); // skip reserved bytes
|
||||||
m_name = reader.readTerminatedString(m_hdlrAtom->totalSize() - 12 - 4 - 12, 0);
|
if((tmp = m_istream->peek()) == m_hdlrAtom->dataSize() - 12 - 4 - 8 - 1) {
|
||||||
|
// assume size prefixed string (seems to appear in QuickTime files)
|
||||||
|
m_istream->seekg(1, ios_base::cur);
|
||||||
|
m_name = reader.readString(tmp);
|
||||||
|
} else {
|
||||||
|
// assume null terminated string (appears in MP4 files)
|
||||||
|
m_name = reader.readTerminatedString(m_hdlrAtom->dataSize() - 12 - 4 - 8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// read stco atom (only chunk count)
|
// read stco atom (only chunk count)
|
||||||
m_chunkOffsetSize = (m_stcoAtom->id() == Mp4AtomIds::ChunkOffset64) ? 8 : 4;
|
m_chunkOffsetSize = (m_stcoAtom->id() == Mp4AtomIds::ChunkOffset64) ? 8 : 4;
|
||||||
m_istream->seekg(m_stcoAtom->dataOffset() + 4);
|
m_istream->seekg(m_stcoAtom->dataOffset() + 4);
|
||||||
m_chunkCount = reader.readUInt32BE();
|
m_chunkCount = reader.readUInt32BE();
|
||||||
|
|
||||||
// read stsd atom
|
// read stsd atom
|
||||||
m_istream->seekg(m_stsdAtom->dataOffset() + 4); // seek to beg, skip size, name, version and flags
|
m_istream->seekg(m_stsdAtom->dataOffset() + 4); // seek to beg, skip size, name, version and flags
|
||||||
uint32 entryCount = reader.readUInt32BE();
|
uint32 entryCount = reader.readUInt32BE();
|
||||||
Mp4Atom *esDescParentAtom = nullptr;
|
Mp4Atom *esDescParentAtom = nullptr;
|
||||||
uint16 tmp;
|
|
||||||
if(entryCount > 0) {
|
if(entryCount > 0) {
|
||||||
try {
|
try {
|
||||||
for(Mp4Atom *codecConfigContainerAtom = m_stsdAtom->firstChild(); codecConfigContainerAtom; codecConfigContainerAtom = codecConfigContainerAtom->nextSibling()) {
|
for(Mp4Atom *codecConfigContainerAtom = m_stsdAtom->firstChild(); codecConfigContainerAtom; codecConfigContainerAtom = codecConfigContainerAtom->nextSibling()) {
|
||||||
|
@ -1456,6 +1472,7 @@ void Mp4Track::internalParseHeader()
|
||||||
addNotification(NotificationType::Critical, "Unable to parse child atoms of \"stsd\"-atom.", context);
|
addNotification(NotificationType::Critical, "Unable to parse child atoms of \"stsd\"-atom.", context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read stsz atom which holds the sample size table
|
// read stsz atom which holds the sample size table
|
||||||
m_sampleSizes.clear();
|
m_sampleSizes.clear();
|
||||||
m_size = m_sampleCount = 0;
|
m_size = m_sampleCount = 0;
|
||||||
|
@ -1527,6 +1544,7 @@ void Mp4Track::internalParseHeader()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no sample sizes found, search for trun atoms
|
// no sample sizes found, search for trun atoms
|
||||||
uint64 totalDuration = 0;
|
uint64 totalDuration = 0;
|
||||||
for(Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(MovieFragment, true); moofAtom; moofAtom = moofAtom->siblingById(MovieFragment, false)) {
|
for(Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(MovieFragment, true); moofAtom; moofAtom = moofAtom->siblingById(MovieFragment, false)) {
|
||||||
|
@ -1654,6 +1672,7 @@ void Mp4Track::internalParseHeader()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set duration from "trun-information" if the duration has not been determined yet
|
// set duration from "trun-information" if the duration has not been determined yet
|
||||||
if(m_duration.isNull() && totalDuration) {
|
if(m_duration.isNull() && totalDuration) {
|
||||||
uint32 timeScale = m_timeScale;
|
uint32 timeScale = m_timeScale;
|
||||||
|
@ -1664,10 +1683,12 @@ void Mp4Track::internalParseHeader()
|
||||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(totalDuration) / static_cast<double>(timeScale));
|
m_duration = TimeSpan::fromSeconds(static_cast<double>(totalDuration) / static_cast<double>(timeScale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// caluculate average bitrate
|
// caluculate average bitrate
|
||||||
if(m_bitrate < 0.01 && m_bitrate > -0.01) {
|
if(m_bitrate < 0.01 && m_bitrate > -0.01) {
|
||||||
m_bitrate = (static_cast<double>(m_size) * 0.0078125) / m_duration.totalSeconds();
|
m_bitrate = (static_cast<double>(m_size) * 0.0078125) / m_duration.totalSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
// read stsc atom (only number of entries)
|
// read stsc atom (only number of entries)
|
||||||
m_istream->seekg(m_stscAtom->dataOffset() + 4);
|
m_istream->seekg(m_stscAtom->dataOffset() + 4);
|
||||||
m_sampleToChunkEntryCount = reader.readUInt32BE();
|
m_sampleToChunkEntryCount = reader.readUInt32BE();
|
||||||
|
|
|
@ -47,6 +47,7 @@ enum Sig32 : uint32
|
||||||
Mp4 = 0x66747970u,
|
Mp4 = 0x66747970u,
|
||||||
Ogg = 0x4F676753u,
|
Ogg = 0x4F676753u,
|
||||||
PhotoshopDocument = 0x38425053u,
|
PhotoshopDocument = 0x38425053u,
|
||||||
|
QuickTime = 0x6D6F6F76u,
|
||||||
Riff = 0x52494646u,
|
Riff = 0x52494646u,
|
||||||
RiffWave =0x57415645u,
|
RiffWave =0x57415645u,
|
||||||
TiffBigEndian = 0x4D4D002Au,
|
TiffBigEndian = 0x4D4D002Au,
|
||||||
|
@ -124,6 +125,8 @@ ContainerFormat parseSignature(const char *buffer, int bufferSize)
|
||||||
switch(sig & 0x00000000FFFFFFFF) { // check 32-bit signatures @ bit 31
|
switch(sig & 0x00000000FFFFFFFF) { // check 32-bit signatures @ bit 31
|
||||||
case Mp4:
|
case Mp4:
|
||||||
return ContainerFormat::Mp4;
|
return ContainerFormat::Mp4;
|
||||||
|
case QuickTime:
|
||||||
|
return ContainerFormat::QuickTime;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -285,6 +288,7 @@ const char *containerFormatAbbreviation(ContainerFormat containerFormat, MediaTy
|
||||||
case ContainerFormat::Bzip2: return "bz";
|
case ContainerFormat::Bzip2: return "bz";
|
||||||
case ContainerFormat::Gzip: return "gz";
|
case ContainerFormat::Gzip: return "gz";
|
||||||
case ContainerFormat::Lzip: return "lz";
|
case ContainerFormat::Lzip: return "lz";
|
||||||
|
case ContainerFormat::QuickTime: return "mov";
|
||||||
case ContainerFormat::Zip: return "zip";
|
case ContainerFormat::Zip: return "zip";
|
||||||
case ContainerFormat::SevenZ: return "7z";
|
case ContainerFormat::SevenZ: return "7z";
|
||||||
default: return "";
|
default: return "";
|
||||||
|
@ -367,6 +371,8 @@ const char *containerFormatName(ContainerFormat containerFormat)
|
||||||
return "lzip compressed file";
|
return "lzip compressed file";
|
||||||
case ContainerFormat::SevenZ:
|
case ContainerFormat::SevenZ:
|
||||||
return "7z archive";
|
return "7z archive";
|
||||||
|
case ContainerFormat::QuickTime:
|
||||||
|
return "Quick Time";
|
||||||
case ContainerFormat::Zip:
|
case ContainerFormat::Zip:
|
||||||
return "ZIP archive";
|
return "ZIP archive";
|
||||||
default:
|
default:
|
||||||
|
@ -445,6 +451,8 @@ const char *containerMimeType(ContainerFormat containerFormat, MediaType mediaTy
|
||||||
return "application/x-rar-compressed";
|
return "application/x-rar-compressed";
|
||||||
case ContainerFormat::Lzip:
|
case ContainerFormat::Lzip:
|
||||||
return "application/x-lzip";
|
return "application/x-lzip";
|
||||||
|
case ContainerFormat::QuickTime:
|
||||||
|
return "video/quicktime";
|
||||||
case ContainerFormat::Zip:
|
case ContainerFormat::Zip:
|
||||||
return "application/zip";
|
return "application/zip";
|
||||||
case ContainerFormat::SevenZ:
|
case ContainerFormat::SevenZ:
|
||||||
|
|
|
@ -50,6 +50,7 @@ enum class ContainerFormat
|
||||||
WindowsIcon, /**< Microsoft Windows Icon */
|
WindowsIcon, /**< Microsoft Windows Icon */
|
||||||
SevenZ, /**< 7z archive */
|
SevenZ, /**< 7z archive */
|
||||||
Lzip, /**< lz compressed file */
|
Lzip, /**< lz compressed file */
|
||||||
|
QuickTime, /**< QuickTime container */
|
||||||
Zip /**< ZIP archive */
|
Zip /**< ZIP archive */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue