improved media format detection; other minor improvements

This commit is contained in:
Martchus 2015-06-07 00:18:28 +02:00
parent 221a690311
commit c452b009ae
26 changed files with 1583 additions and 353 deletions

View File

@ -32,7 +32,7 @@ AbstractTrack::AbstractTrack(istream &inputStream, ostream &outputStream, uint64
m_writer(BinaryWriter(&outputStream)), m_writer(BinaryWriter(&outputStream)),
m_startOffset(startOffset), m_startOffset(startOffset),
m_headerValid(false), m_headerValid(false),
m_format(MediaFormat::Unknown), m_format(),
m_mediaType(MediaType::Unknown), m_mediaType(MediaType::Unknown),
m_version(0.0), m_version(0.0),
m_size(0), m_size(0),
@ -79,22 +79,13 @@ AbstractTrack::~AbstractTrack()
/*! /*!
* \brief Returns the format of the track as C-style string if known; otherwise * \brief Returns the format of the track as C-style string if known; otherwise
* returns the format abbreviation or an empty string. * returns the format abbreviation or an empty string.
* \remarks
* - The caller must not free the returned string.
* - The string might get invalidated when the track is (re)parsed.
*/ */
const char *AbstractTrack::formatName() const const char *AbstractTrack::formatName() const
{ {
if(!m_formatName.empty()) { return m_format || m_formatName.empty() ? m_format.name() : m_formatName.c_str();
return m_formatName.c_str();
}
const char *formatName = mediaFormatName(m_format);
if(*formatName == 0) {
if(!m_formatId.empty()) {
return m_formatId.c_str();
} else {
return "unknown";
}
} else {
return formatName;
}
} }
/*! /*!
@ -103,43 +94,8 @@ const char *AbstractTrack::formatName() const
*/ */
const char *AbstractTrack::formatAbbreviation() const const char *AbstractTrack::formatAbbreviation() const
{ {
if(!m_formatId.empty()) { const char *abbr = m_format.abbreviation();
return m_formatId.c_str(); return *abbr || m_formatId.empty() ? m_format.abbreviation() : m_formatId.c_str();
}
switch(m_format) {
case MediaFormat::Pcm:
return "PCM";
case MediaFormat::Mpeg1:
return "MPEG-1";
case MediaFormat::Mpeg2:
return "MPEG-2";
case MediaFormat::MpegL1:
return "MP1";
case MediaFormat::MpegL2:
return "MP2";
case MediaFormat::MpegL3:
return "MP3";
case MediaFormat::Aac:
return "AAC";
case MediaFormat::Png:
return "PNG";
case MediaFormat::Jpeg:
return "JPEG";
case MediaFormat::Mpeg4Avc:
return "AVC";
case MediaFormat::Mpeg4Asp:
return "ASP";
case MediaFormat::Mpeg4:
return "MPEG-4";
case MediaFormat::Gif:
return "GIF";
case MediaFormat::Tiff:
return "TIFF";
case MediaFormat::Ac3:
return "AC3";
default:
return "";
}
} }
/*! /*!
@ -148,11 +104,11 @@ const char *AbstractTrack::formatAbbreviation() const
const char *AbstractTrack::mediaTypeName() const const char *AbstractTrack::mediaTypeName() const
{ {
switch(m_mediaType) { switch(m_mediaType) {
case MediaType::Acoustic: case MediaType::Audio:
return "Audio"; return "Audio";
case MediaType::Visual: case MediaType::Video:
return "Video"; return "Video";
case MediaType::Textual: case MediaType::Text:
return "Subititle"; return "Subititle";
case MediaType::Hint: case MediaType::Hint:
return "Hint"; return "Hint";

View File

@ -4,6 +4,7 @@
#include "statusprovider.h" #include "statusprovider.h"
#include "size.h" #include "size.h"
#include "margin.h" #include "margin.h"
#include "mediaformat.h"
#include <c++utilities/conversion/types.h> #include <c++utilities/conversion/types.h>
#include <c++utilities/io/binaryreader.h> #include <c++utilities/io/binaryreader.h>
@ -17,7 +18,7 @@
namespace Media { namespace Media {
enum class MediaType; enum class MediaType;
enum class MediaFormat; enum class GeneralMediaFormat;
/*! /*!
* \brief Specifies the track type. * \brief Specifies the track type.

View File

@ -4,6 +4,15 @@
namespace Media { namespace Media {
/*!
* \struct Media::SpsInfo
* \brief The SpsInfo struct holds the sequence parameter set.
*/
/*!
* \brief SpsInfo::parse
* \param stream
*/
void SpsInfo::parse(std::istream &stream) void SpsInfo::parse(std::istream &stream)
{ {
static auto highLevelProfileIds = std::unordered_map<unsigned int, bool> { static auto highLevelProfileIds = std::unordered_map<unsigned int, bool> {

View File

@ -27,6 +27,72 @@ namespace Media {
template <class ImplementationType> template <class ImplementationType>
class GenericFileElement; class GenericFileElement;
/*!
* \class Media::FileElementIterator
* \brief The FileElementIterator class helps iterating through the childs of a FileElement.
*/
template<typename ImplementationType>
class FileElementIterator
{
public:
FileElementIterator(ImplementationType *element = nullptr);
ImplementationType *operator *();
const ImplementationType *operator *() const;
operator bool() const;
FileElementIterator<ImplementationType> &operator ++();
private:
ImplementationType *m_current;
};
/*!
* \brief Constructs a new iterator for the specified \a element.
*/
template<typename ImplementationType>
inline FileElementIterator<ImplementationType>::FileElementIterator(ImplementationType *element) :
m_current(element)
{}
/*!
* \brief Returns a reference to the current element.
*/
template<typename ImplementationType>
inline ImplementationType *FileElementIterator<ImplementationType>::operator *()
{
return m_current;
}
/*!
* \brief Returns a reference the current element (constant).
*/
template<typename ImplementationType>
inline const ImplementationType *FileElementIterator<ImplementationType>::operator *() const
{
return m_current;
}
/*!
* \brief Moves to the next sibling.
*/
template<typename ImplementationType>
inline FileElementIterator<ImplementationType> &FileElementIterator<ImplementationType>::operator ++()
{
m_current->parse(); // ensure the current element has been parsed
m_current = m_current->nextSibling();
return *this;
}
/*!
* \brief Returns whether the iterator points to an element.
*/
template<typename ImplementationType>
inline FileElementIterator<ImplementationType>::operator bool() const
{
return m_current != nullptr;
}
/*! /*!
* \class Media::FileElementTraits * \class Media::FileElementTraits
* \brief Defines traits for the specified \a ImplementationType. * \brief Defines traits for the specified \a ImplementationType.
@ -66,7 +132,7 @@ public:
/*! /*!
* \brief Specifies the type used to store data sizes. * \brief Specifies the type used to store data sizes.
*/ */
typedef uint64 dataSizeType; typedef typename FileElementTraits<ImplementationType>::dataSizeType dataSizeType;
/*! /*!
* \brief Specifies the type of the actual implementation. * \brief Specifies the type of the actual implementation.
@ -106,6 +172,10 @@ public:
implementationType* subelementByPath(std::list<identifierType> &path); implementationType* subelementByPath(std::list<identifierType> &path);
implementationType* childById(const identifierType &id); implementationType* childById(const identifierType &id);
implementationType* siblingById(const identifierType &id, bool includeThis = false); implementationType* siblingById(const identifierType &id, bool includeThis = false);
FileElementIterator<implementationType> begin();
FileElementIterator<implementationType> end();
const FileElementIterator<implementationType> begin() const;
const FileElementIterator<implementationType> end() const;
bool isParent() const; bool isParent() const;
bool isPadding() const; bool isPadding() const;
uint64 firstChildOffset() const; uint64 firstChildOffset() const;
@ -140,6 +210,7 @@ private:
/*! /*!
* \brief Constructs a new top level file element with the specified \a container at the specified \a startOffset. * \brief Constructs a new top level file element with the specified \a container at the specified \a startOffset.
* \remarks The available size is obtained using the stream of the \a container.
*/ */
template <class ImplementationType> template <class ImplementationType>
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::containerType &container, uint64 startOffset) : GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::containerType &container, uint64 startOffset) :
@ -339,6 +410,9 @@ inline uint64 GenericFileElement<ImplementationType>::totalSize() const
/*! /*!
* \brief Returns maximum total size. * \brief Returns maximum total size.
*
* This is usually the size of the file for top-level elements and
* the remaining size of the parent for non-top-level elements.
*/ */
template <class ImplementationType> template <class ImplementationType>
inline uint64 GenericFileElement<ImplementationType>::maxTotalSize() const inline uint64 GenericFileElement<ImplementationType>::maxTotalSize() const
@ -528,6 +602,42 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
return nullptr; return nullptr;
} }
/*!
* \brief Returns an iterator for iterating over the element's childs.
*/
template <class ImplementationType>
FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::begin()
{
return FileElementIterator<implementationType>(firstChild());
}
/*!
* \brief Returns an iterator for iterating over the element's childs (constant).
*/
template <class ImplementationType>
const FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::begin() const
{
return FileElementIterator<implementationType>(firstChild());
}
/*!
* \brief Returns an invalid iterator.
*/
template <class ImplementationType>
FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::end()
{
return FileElementIterator<ImplementationType>();
}
/*!
* \brief Returns an invalid iterator.
*/
template <class ImplementationType>
const FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::end() const
{
return FileElementIterator<ImplementationType>();
}
/*! /*!
* \brief Returns an indication whether this instance is a parent element. * \brief Returns an indication whether this instance is a parent element.
*/ */

View File

@ -34,6 +34,13 @@ EbmlElement::EbmlElement(MatroskaContainer &container, uint64 startOffset) :
GenericFileElement<EbmlElement>(container, startOffset) GenericFileElement<EbmlElement>(container, startOffset)
{} {}
/*!
* \brief Constructs a new top level element with the specified \a container at the specified \a startOffset.
*/
EbmlElement::EbmlElement(MatroskaContainer &container, uint64 startOffset, uint64 maxSize) :
GenericFileElement<EbmlElement>(container, startOffset, maxSize)
{}
/*! /*!
* \brief Constructs a new sub level element with the specified \a parent at the specified \a startOffset. * \brief Constructs a new sub level element with the specified \a parent at the specified \a startOffset.
*/ */
@ -129,7 +136,7 @@ void EbmlElement::internalParse()
if(parent()) { if(parent()) {
m_nextSibling.reset(new EbmlElement(*(parent()), startOffset() + totalSize())); m_nextSibling.reset(new EbmlElement(*(parent()), startOffset() + totalSize()));
} else { } else {
m_nextSibling = make_unique<EbmlElement>(container(), startOffset() + totalSize()); m_nextSibling.reset(new EbmlElement(container(), startOffset() + totalSize(), maxTotalSize() - totalSize()));
} }
} else { } else {
m_nextSibling.reset(); m_nextSibling.reset();

View File

@ -35,6 +35,11 @@ public:
*/ */
typedef uint32 identifierType; typedef uint32 identifierType;
/*!
* \brief The type used to store element sizes is an unsigned 64-bit integer.
*/
typedef uint64 dataSizeType;
/*! /*!
* \brief The implementation type is EbmlElement. * \brief The implementation type is EbmlElement.
*/ */
@ -67,6 +72,7 @@ public:
protected: protected:
EbmlElement(EbmlElement &parent, uint64 startOffset); EbmlElement(EbmlElement &parent, uint64 startOffset);
EbmlElement(MatroskaContainer &container, uint64 startOffset, uint64 maxSize);
void internalParse(); void internalParse();

View File

@ -6,7 +6,10 @@
#include "../mediaformat.h" #include "../mediaformat.h"
#include "../exceptions.h" #include "../exceptions.h"
#include <c++utilities/conversion/stringconversion.h>
using namespace std; using namespace std;
using namespace ConversionUtilities;
namespace Media { namespace Media {
@ -37,6 +40,144 @@ TrackType MatroskaTrack::type() const
return TrackType::MatroskaTrack; return TrackType::MatroskaTrack;
} }
/*!
* \brief Returns the MediaFormat for the specified Matroska codec ID.
*/
MediaFormat MatroskaTrack::codecIdToMediaFormat(const string &codecId)
{
auto parts = splitString<vector<string> >(codecId, "/", EmptyPartsTreat::Keep, 3);
parts.resize(3);
const auto &part1 = parts[0], &part2 = parts[1], &part3 = parts[2];
MediaFormat fmt;
if(part1 == "V_MS" && part2 == "VFW" && part3 == "FOURCC") {
fmt.general = GeneralMediaFormat::MicrosoftVideoCodecManager;
} else if(part1 == "V_UNCOMPRESSED") {
fmt.general = GeneralMediaFormat::UncompressedVideoFrames;
} else if(part1 == "V_MPEG4") {
fmt.general = GeneralMediaFormat::Mpeg4Video;
if(part2 == "ISO") {
if(part3 == "SP") {
fmt.sub = SubFormats::Mpeg4Sp;
} else if(part3 == "ASP") {
fmt.sub = SubFormats::Mpeg4Asp;
} else if(part3 == "AP") {
fmt.sub = SubFormats::Mpeg4Avc;
}
} else if(part2 == "MS" && part3 == "V3") {
fmt.sub = SubFormats::Mpeg4MsV3;
}
} else if(part1 == "V_MPEG1") {
fmt.general = GeneralMediaFormat::Mpeg1Video;
} else if(part1 == "V_MPEG2") {
fmt.general = GeneralMediaFormat::Mpeg2Video;
} else if(part1 == "V_REAL") {
fmt.general = GeneralMediaFormat::RealVideo;
} else if(part1 == "V_QUICKTIME") {
fmt.general = GeneralMediaFormat::QuicktimeVideo;
} else if(part1 == "V_THEORA") {
fmt.general = GeneralMediaFormat::Theora;
} else if(part1 == "V_PRORES") {
fmt.general = GeneralMediaFormat::ProRes;
} else if(part1 == "A_MPEG") {
fmt.general = GeneralMediaFormat::Mpeg1Audio;
if(part2 == "L1") {
fmt.sub = SubFormats::Mpeg1Layer1;
} else if(part2 == "L2") {
fmt.sub = SubFormats::Mpeg1Layer2;
} else if(part2 == "L3") {
fmt.sub = SubFormats::Mpeg1Layer3;
}
} else if(part1 == "A_PCM") {
fmt.general = GeneralMediaFormat::Pcm;
if(part2 == "INT") {
if(part3 == "BIG") {
fmt.sub = SubFormats::PcmIntBe;
} else if(part3 == "LIT") {
fmt.sub = SubFormats::PcmIntLe;
}
} else if (part2 == "FLOAT" && part3 == "IEEE") {
fmt.sub = SubFormats::PcmFloatIeee;
}
} else if(part1 == "A_MPC") {
fmt.general = GeneralMediaFormat::Mpc;
} else if(part1 == "A_AC3") {
fmt.general = GeneralMediaFormat::Ac3;
} else if(part1 == "A_ALAC") {
fmt.general = GeneralMediaFormat::Alac;
} else if(part1 == "A_DTS") {
fmt.general = GeneralMediaFormat::Dts;
if(part2 == "EXPRESS") {
fmt.sub = SubFormats::DtsExpress;
} else if(part2 == "LOSSLESS") {
fmt.sub = SubFormats::DtsLossless;
}
} else if(part1 == "A_VORBIS") {
fmt.general = GeneralMediaFormat::Vorbis;
} else if(part1 == "A_FLAC") {
fmt.general = GeneralMediaFormat::Flac;
} else if(part1 == "A_REAL") {
fmt.general = GeneralMediaFormat::RealAudio;
} else if(part1 == "A_MS" && part2 == "ACM") {
fmt.general = GeneralMediaFormat::MicrosoftAudioCodecManager;
} else if(part1 == "A_AAC") {
fmt.general = GeneralMediaFormat::Aac;
if(part2 == "MPEG2") {
if(part3 == "MAIN") {
fmt.sub = SubFormats::AacMpeg2MainProfile;
} else if(part3 == "LC") {
fmt.sub = SubFormats::AacMpeg2LowComplexityProfile;
} else if(part3 == "SBR") {
fmt.sub = SubFormats::AacMpeg2SpectralBandReplicationProfile;
} else if(part3 == "SSR") {
fmt.sub = SubFormats::AacMpeg2ScalableSamplingRateProfile;
}
} else if(part2 == "MPEG4") {
if(part3 == "MAIN") {
fmt.sub = SubFormats::AacMpeg4MainProfile;
} else if(part3 == "LC") {
fmt.sub = SubFormats::AacMpeg4LowComplexityProfile;
} else if(part3 == "SBR") {
fmt.sub = SubFormats::AacMpeg4SpectralBandReplicationProfile;
} else if(part3 == "SSR") {
fmt.sub = SubFormats::AacMpeg4ScalableSamplingRateProfile;
} else if(part3 == "LTP") {
fmt.sub = SubFormats::AacMpeg4LongTermPredictionProfile;
}
}
} else if(part1 == "A_QUICKTIME") {
fmt.general = GeneralMediaFormat::QuicktimeAudio;
} else if(part1 == "A_TTA1") {
fmt.general = GeneralMediaFormat::Tta;
} else if(part1 == "A_WAVPACK4") {
fmt.general = GeneralMediaFormat::WavPack;
} else if(part1 == "S_TEXT") {
fmt.general = GeneralMediaFormat::TextSubtitle;
if(part2 == "UTF8") {
fmt.sub = SubFormats::TextSubBasicUtf8;
} else if(part2 == "SSA") {
fmt.sub = SubFormats::TextSubSubtitlesFormat;
} else if(part2 == "ASS") {
fmt.sub = SubFormats::TextSubAdvancedSubtitlesFormat;
} else if(part2 == "USF") {
fmt.sub = SubFormats::TextSubUniversalSubtitleFormat;
}
} else if(part1 == "S_IMAGE") {
fmt.general = GeneralMediaFormat::ImageSubtitle;
if(part2 == "BMP") {
fmt.sub = SubFormats::ImgSubBmp;
}
} else if(part1 == "S_VOBSUB") {
fmt.general = GeneralMediaFormat::VobSub;
} else if(part1 == "S_KATE") {
fmt.general = GeneralMediaFormat::OggKate;
} else if(part1 == "B_VOBBTN") {
fmt.general = GeneralMediaFormat::VobBtn;
} else if(part1 == "V_MSWMV") {
fmt.general = GeneralMediaFormat::Vc1;
}
return fmt;
}
void MatroskaTrack::internalParseHeader() void MatroskaTrack::internalParseHeader()
{ {
const string context("parsing header of Matroska track"); const string context("parsing header of Matroska track");
@ -61,13 +202,13 @@ void MatroskaTrack::internalParseHeader()
case MatroskaIds::TrackType: case MatroskaIds::TrackType:
switch(trackInfoElement->readUInteger()) { switch(trackInfoElement->readUInteger()) {
case MatroskaTrackType::Video: case MatroskaTrackType::Video:
m_mediaType = MediaType::Visual; m_mediaType = MediaType::Video;
break; break;
case MatroskaTrackType::Audio: case MatroskaTrackType::Audio:
m_mediaType = MediaType::Acoustic; m_mediaType = MediaType::Audio;
break; break;
case MatroskaTrackType::Subtitle: case MatroskaTrackType::Subtitle:
m_mediaType = MediaType::Textual; m_mediaType = MediaType::Text;
break; break;
default: default:
m_mediaType = MediaType::Unknown; m_mediaType = MediaType::Unknown;
@ -158,7 +299,10 @@ void MatroskaTrack::internalParseHeader()
m_language = trackInfoElement->readString(); m_language = trackInfoElement->readString();
break; break;
case MatroskaIds::CodecID: case MatroskaIds::CodecID:
m_formatId = trackInfoElement->readString(); m_format = codecIdToMediaFormat(m_formatId = trackInfoElement->readString());
if(m_formatName.empty()) {
m_formatName = m_format ? string(m_format.name()) : m_formatId;
}
break; break;
case MatroskaIds::CodecName: case MatroskaIds::CodecName:
m_formatName = trackInfoElement->readString(); m_formatName = trackInfoElement->readString();
@ -181,7 +325,7 @@ void MatroskaTrack::internalParseHeader()
default: ; default: ;
} }
switch(m_mediaType) { switch(m_mediaType) {
case MediaType::Visual: case MediaType::Video:
if(m_fps == 0 && defaultDuration != 0) { if(m_fps == 0 && defaultDuration != 0) {
m_fps = 1000000000.0 / static_cast<double>(defaultDuration); m_fps = 1000000000.0 / static_cast<double>(defaultDuration);
} }

View File

@ -18,6 +18,8 @@ public:
TrackType type() const; TrackType type() const;
static MediaFormat codecIdToMediaFormat(const std::string &codecId);
protected: protected:
void internalParseHeader(); void internalParseHeader();

View File

@ -537,18 +537,11 @@ const char *MediaFileInfo::containerFormatAbbreviation() const
case ContainerFormat::Ogg: case ContainerFormat::Ogg:
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
case ContainerFormat::Mp4: case ContainerFormat::Mp4:
mediaType = hasTracksOfType(MediaType::Visual) ? MediaType::Visual : MediaType::Acoustic; mediaType = hasTracksOfType(MediaType::Video) ? MediaType::Video : MediaType::Audio;
break; break;
case ContainerFormat::MpegAudioFrames: case ContainerFormat::MpegAudioFrames:
if(m_mpegAudioFrameStream) { if(m_mpegAudioFrameStream) {
switch(m_mpegAudioFrameStream->format()) { version = m_mpegAudioFrameStream->format().sub;
case MediaFormat::MpegL1:
version = 1;
case MediaFormat::MpegL2:
version = 2;
default:
version = 3;
}
} }
break; break;
default: default:
@ -597,17 +590,17 @@ const char *MediaFileInfo::mimeType() const
case ContainerFormat::MpegAudioFrames: case ContainerFormat::MpegAudioFrames:
return "audio/mpeg"; return "audio/mpeg";
case ContainerFormat::Mp4: case ContainerFormat::Mp4:
if(hasTracksOfType(MediaType::Visual)) { if(hasTracksOfType(MediaType::Video)) {
return "video/mp4"; return "video/mp4";
} }
return "audio/mp4"; return "audio/mp4";
case ContainerFormat::Ogg: case ContainerFormat::Ogg:
if(hasTracksOfType(MediaType::Visual)) { if(hasTracksOfType(MediaType::Video)) {
return "video/ogg"; return "video/ogg";
} }
return "audio/ogg"; return "audio/ogg";
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
if(hasTracksOfType(MediaType::Visual)) { if(hasTracksOfType(MediaType::Video)) {
return "video/x-matroska"; return "video/x-matroska";
} }
return "audio/x-matroska"; return "audio/x-matroska";
@ -699,7 +692,7 @@ bool MediaFileInfo::hasTracksOfType(MediaType type) const
if(!areTracksParsed()) { if(!areTracksParsed()) {
return false; return false;
} }
if(type == MediaType::Acoustic && (m_waveAudioStream || m_mpegAudioFrameStream)) { if(type == MediaType::Audio && (m_waveAudioStream || m_mpegAudioFrameStream)) {
return true; return true;
} else if(m_container) { } else if(m_container) {
for(size_t i = 0, count = m_container->trackCount(); i < count; ++i) { for(size_t i = 0, count = m_container->trackCount(); i < count; ++i) {
@ -907,6 +900,7 @@ bool MediaFileInfo::areChaptersSupported() const
} }
switch(m_containerFormat) { switch(m_containerFormat) {
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
case ContainerFormat::Webm:
return true; return true;
default: default:
return false; return false;
@ -923,6 +917,7 @@ bool MediaFileInfo::areAttachmentsSupported() const
} }
switch(m_containerFormat) { switch(m_containerFormat) {
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
case ContainerFormat::Webm:
return true; return true;
default: default:
return false; return false;
@ -943,6 +938,7 @@ bool MediaFileInfo::areTracksSupported() const
case ContainerFormat::RiffWave: case ContainerFormat::RiffWave:
case ContainerFormat::Ogg: case ContainerFormat::Ogg:
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
case ContainerFormat::Webm:
return true; return true;
default: default:
return false; return false;
@ -962,6 +958,7 @@ bool MediaFileInfo::areTagsSupported() const
case ContainerFormat::MpegAudioFrames: case ContainerFormat::MpegAudioFrames:
case ContainerFormat::Ogg: case ContainerFormat::Ogg:
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
case ContainerFormat::Webm:
return true; return true;
default: default:
return false; return false;

View File

@ -2,74 +2,282 @@
namespace Media { namespace Media {
using namespace SubFormats;
/*! /*!
* \brief Returns the name of the specified media format as C-style string. * \class Media::MediaFormat
* \brief The MediaFormat class specifies the format of media data.
*/
/*!
* \brief Returns the name of the media format as C-style string.
* *
* Returns an empty string if no name is available. * Returns an empty string if no name is available.
*/ */
const char *mediaFormatName(MediaFormat mediaFormat) const char *MediaFormat::name() const
{ {
switch(mediaFormat) { switch(general) {
case MediaFormat::Pcm: case GeneralMediaFormat::Aac:
return "Puls-Code-Modulation"; switch(sub) {
case MediaFormat::Mpeg1: case AacMpeg2MainProfile: return "Advanced Audio Coding Main Profile";
return "MPEG-1"; case AacMpeg2LowComplexityProfile: return "Advanced Audio Coding Low Complexity Profile";
case MediaFormat::Mpeg2: case AacMpeg2SpectralBandReplicationProfile: return "Advanced Audio Coding Low Complexity with Spectral Band Replication Profile";
return "MPEG-2"; case AacMpeg2ScalableSamplingRateProfile: return "Advanced Audio Coding Scalable Sampling Rate Profile";
case MediaFormat::MpegL1: case AacMpeg4MainProfile: return "Advanced Audio Coding Main Profile";
return "MPEG-1 Layer 1"; case AacMpeg4LowComplexityProfile: return "Advanced Audio Coding Low Complexity Profile";
case MediaFormat::MpegL2: case AacMpeg4SpectralBandReplicationProfile: return "Advanced Audio Coding Low Complexity with Spectral Band Replication Profile";
return "MPEG-1 Layer 2"; case AacMpeg4ScalableSamplingRateProfile: return "Advanced Audio Coding Scaleable Sampling Rate Profile";
case MediaFormat::MpegL3: case AacMpeg4LongTermPredictionProfile: return "Advanced Audio Coding Scalable Sampling Rate Profile";
return "MPEG-1 Layer 3"; default: return "Advanced Audio Coding";
case MediaFormat::Aac: }
return "Advanced Audio Coding"; case GeneralMediaFormat::Ac3: return "Dolby Digital";
case MediaFormat::Vorbis: case GeneralMediaFormat::Ac4: return "AC-4";
return "Vorbis"; case GeneralMediaFormat::AdpcmAcm: return "ADPCM ACM";
case MediaFormat::Png: case GeneralMediaFormat::AfxStream: return "AFX Stream";
return "Portable Network Graphics"; case GeneralMediaFormat::Alac: return "Apple Lossless Audio Codec";
case MediaFormat::Jpeg: case GeneralMediaFormat::Als: return "ALS";
return "JPEG File Interchange Format"; case GeneralMediaFormat::Bitmap: return "Windows Bitmap";
case MediaFormat::Mpeg4Sp: case GeneralMediaFormat::Dirac: return "Dirac";
return "H.264/MPEG-4 Simple profile"; case GeneralMediaFormat::Dts: return "DTS";
case MediaFormat::Mpeg4Avc: switch(sub) {
return "H.264/MPEG-4 Advanced Video Coding"; case DtsLossless: return "DTS Lossless";
case MediaFormat::Mpeg4Asp: case DtsExpress: return "DTS Express";
return "H.263/MPEG-4 Advanced Simple Profile"; default: return "DTS";
case MediaFormat::Mpeg4: }
return "MPEG-4"; case GeneralMediaFormat::DtsHd: return "DTS-HD";
case MediaFormat::Gif: switch(sub) {
return "Graphics Interchange Format"; case DtsHdHighResolution: return "DTS-HD High Resolution";
case MediaFormat::Tiff: case DtsHdMasterAudio: return "DTS-HD Master Audio";
return "Tagged Image File Format"; case DtsExpress: return "DTS-HD Express";
case MediaFormat::UncompressedRgb: default: return "DTS-HD";
return "Uncompressed RGB"; }
case MediaFormat::AdpcmAcm: case GeneralMediaFormat::EAc3: return "Dolby Digital Plus";
return "Microsoft ADPCM-ACM code 2"; case GeneralMediaFormat::Evrc: return "EVRC";
case MediaFormat::ImaadpcmAcm: case GeneralMediaFormat::Flac: return "Free Lossless Audio Codec";
return "DVI/Intel IMAADPCM-ACM code 17"; case GeneralMediaFormat::FontDataStream: return "Font Data Stream";
case MediaFormat::Ac3: case GeneralMediaFormat::Gif: return "GIF";
return "Dolby Digital (AC-3)"; case GeneralMediaFormat::Gpp2Cmf: return "3GPP2 Compact Multimedia Format (CMF)";
case MediaFormat::Ac4: case GeneralMediaFormat::ImaadpcmAcm: return "IMAADPCM ACM";
return "Dolby Digital (AC-4)"; case GeneralMediaFormat::ImageSubtitle:
case MediaFormat::RealVideo: switch(sub) {
return "Real Video"; case SubFormats::ImgSubBmp: return "Bitmap subtitle";
case MediaFormat::RealAudio: default: return "Image subtitle";
return "Real Audio"; }
case MediaFormat::QuicktimeVideo: case GeneralMediaFormat::InteractionStream: return "Interaction Stream";
return "Quicktime video"; case GeneralMediaFormat::Jpeg: return "JPEG";
case MediaFormat::QuicktimeAudio: case GeneralMediaFormat::OggKate: return "Karaoke And Text Encapsulation";
return "Quicktime audio"; case GeneralMediaFormat::MicrosoftAudioCodecManager: return "Microsoft Audio Codec Manager";
case MediaFormat::Dts: case GeneralMediaFormat::MicrosoftVideoCodecManager: return "Microsoft Video Codec Manager";
return "Digital Theatre System"; case GeneralMediaFormat::Mpeg1Audio:
case MediaFormat::Theora: switch(sub) {
return "Theora"; case Mpeg1Layer1: return "MPEG-1 Layer 1";
case MediaFormat::ProRes: case Mpeg1Layer2: return "MPEG-1 Layer 2";
return "Apple ProRes"; case Mpeg1Layer3: return "MPEG-1 Layer 3";
case MediaFormat::Alac: default: return "MPEG-1 Audio";
return "Apple lossless audio codec"; }
default: case GeneralMediaFormat::Mpeg1Video: return "MPEG-1 Video";
return ""; case GeneralMediaFormat::Mpeg2Audio:
switch(sub) {
case Mpeg1Layer1: return "MPEG-2 Layer 1";
case Mpeg1Layer2: return "MPEG-2 Layer 2";
case Mpeg1Layer3: return "MPEG-2 Layer 3";
default: return "MPEG-2 Audio";
}
case GeneralMediaFormat::Mpeg2Video:
switch(sub) {
case Mpeg2SimpleProfile: return "MPEG-2 Video Simple Profile";
case Mpeg2MainProfile: return "MPEG-2 Video Main Profile";
case Mpeg2SnrProfile: return "MPEG-2 Video SNR Profile";
case Mpeg2SpatialProfile: return "MPEG-2 Video Spatial Profile";
case Mpeg2HighProfile: return "MPEG-2 Video High Profile";
case Mpeg2422Profile: return "MPEG-2 Video 422 Profile";
default: return "MPEG-2 Video";
}
case GeneralMediaFormat::Mpeg4Video:
switch(sub) {
case Mpeg4Sp: return "MPEG-4 Simple Profile";
case Mpeg4Asp: return "MPEG-4 Advanced Simple Profile";
case Mpeg4Avc: return "MPEG-4 Advanced Video Coding";
case Mpeg4AvcParams: return "Parameter for MPEG-4 Advanced Video Coding";
case Mpeg4MsV3: return "MPEG-4 Microsoft V3";
default: return "MPEG-4 Visual";
}
case GeneralMediaFormat::Mpc: return "Musepack SV8";
case GeneralMediaFormat::Pcm:
switch(sub) {
case PcmIntBe: return "Pulse Code Modulation (integer, big endian)";
case PcmIntLe: return "Pulse Code Modulation (integer, little endian)";
case PcmFloatIeee: return "Pulse Code Modulation (float, IEEE)";
default: return "Pulse Code Modulation";
}
case GeneralMediaFormat::Png: return "Portable Network Graphics";
case GeneralMediaFormat::ProRes: return "ProRes";
case GeneralMediaFormat::Qcelp: return "QCELP";
case GeneralMediaFormat::QuicktimeAudio: return "Quicktime Audio";
case GeneralMediaFormat::QuicktimeVideo: return "Quicktime Video";
case GeneralMediaFormat::RealAudio: return "Real Audio";
case GeneralMediaFormat::RealVideo: return "Real Video";
case GeneralMediaFormat::Sa0c: return "SAOC";
case GeneralMediaFormat::Smv: return "SMV";
case GeneralMediaFormat::StreamingTextStream: return "Streaming Text Stream";
case GeneralMediaFormat::SynthesizedTextureStream: return "Synthesized Texture Stream";
case GeneralMediaFormat::Systems: return "Systems";
case GeneralMediaFormat::TextSubtitle:
switch(sub) {
case SubFormats::TextSubBasicUtf8: return "UTF-8 Plain Text subtitles";
case SubFormats::TextSubSubtitlesFormat: return "Subtitles Format";
case SubFormats::TextSubAdvancedSubtitlesFormat: return "Advanced Subtitles Format";
case SubFormats::TextSubUniversalSubtitleFormat: return "Universal Subtitle Format";
default: return "Text subtitle";
}
case GeneralMediaFormat::Theora: return "Theora";
case GeneralMediaFormat::Tiff: return "Tagged Image File Format";
case GeneralMediaFormat::Tta: return "The True Audio";
case GeneralMediaFormat::UncompressedVideoFrames: return "uncompressed video frames";
case GeneralMediaFormat::Vc1: return "Windows Media Video";
case GeneralMediaFormat::VobBtn: return "VobBtn Buttons";
case GeneralMediaFormat::VobSub: return "VobSub";
case GeneralMediaFormat::Vorbis: return "Vorbis";
case GeneralMediaFormat::WavPack: return "WavPack";
default: return "unknown";
}
}
/*!
* \brief Returns the abbreviation of the media format as C-style string.
*
* Returns an empty string if no abbreviation is available.
*/
const char *MediaFormat::abbreviation() const
{
switch(general) {
case GeneralMediaFormat::Aac:
switch(sub) {
case AacMpeg2MainProfile: return "MPEG-2 AAC Main";
case AacMpeg2LowComplexityProfile: return "MPEG-2 AAC-LC";
case AacMpeg2SpectralBandReplicationProfile: return "MPEG-2-SBR";
case AacMpeg2ScalableSamplingRateProfile: return "MPEG-2 AAC-SSR";
case AacMpeg4MainProfile: return "MPEG-4 AAC Main";
case AacMpeg4LowComplexityProfile: return "MPEG-4 AAC-LC";
case AacMpeg4SpectralBandReplicationProfile: return "MPEG-4 AAC-SBR";
case AacMpeg4ScalableSamplingRateProfile: return "MPEG-4 AAC-SSR";
case AacMpeg4LongTermPredictionProfile: return "MPEG-4 AAC-LTP";
default: return "AAC";
}
case GeneralMediaFormat::Ac3: return "AC-3";
case GeneralMediaFormat::Ac4: return "AC-4";
case GeneralMediaFormat::AdpcmAcm: return "ADPCM ACM";
case GeneralMediaFormat::AfxStream: return "AFX";
case GeneralMediaFormat::Alac: return "ALAC";
case GeneralMediaFormat::Als: return "ALS";
case GeneralMediaFormat::Bitmap: return "BMP";
case GeneralMediaFormat::Dirac: return "Dirac";
case GeneralMediaFormat::Dts: return "DTS";
switch(sub) {
case DtsLossless: return "DTS Lossless";
case DtsExpress: return "DTS LBR";
default: return "DTS";
}
case GeneralMediaFormat::DtsHd: return "DTS-HD";
switch(sub) {
case DtsHdHighResolution: return "DTS-HD High Resolution";
case DtsHdMasterAudio: return "DTS-HD Master Audio";
case DtsExpress: return "DTS-HD Express";
default: return "DTS-HD";
}
case GeneralMediaFormat::EAc3: return "E-AC-3";
case GeneralMediaFormat::Evrc: return "EVRC";
case GeneralMediaFormat::Flac: return "FLAC";
case GeneralMediaFormat::FontDataStream: return "FDS";
case GeneralMediaFormat::Gif: return "GIF";
case GeneralMediaFormat::Gpp2Cmf: return "3GPP2 CMF";
case GeneralMediaFormat::ImaadpcmAcm: return "IMAADPCM ACM";
case GeneralMediaFormat::ImageSubtitle:
switch(sub) {
case SubFormats::ImgSubBmp: return "BMP subtitle";
default: return "Image subtitle";
}
case GeneralMediaFormat::InteractionStream: return "Interaction Stream";
case GeneralMediaFormat::Jpeg: return "JPEG";
case GeneralMediaFormat::OggKate: return "OggKate";
case GeneralMediaFormat::MicrosoftAudioCodecManager: return "MS ACM";
case GeneralMediaFormat::MicrosoftVideoCodecManager: return "MS VCM";
case GeneralMediaFormat::Mpeg1Audio:
switch(sub) {
case Mpeg1Layer1: return "MP1";
case Mpeg1Layer2: return "MP2";
case Mpeg1Layer3: return "MP3";
default: return "MPEG-1 Audio";
}
case GeneralMediaFormat::Mpeg1Video: return "MP1";
case GeneralMediaFormat::Mpeg2Audio:
switch(sub) {
case Mpeg1Layer1: return "MP1";
case Mpeg1Layer2: return "MP2";
case Mpeg1Layer3: return "MP3";
default: return "MPEG-2 Audio";
}
case GeneralMediaFormat::Mpeg2Video:
switch(sub) {
case Mpeg2SimpleProfile: return "MPEG-2 SP";
case Mpeg2MainProfile: return "MPEG-2 Main";
case Mpeg2SnrProfile: return "MPEG-2 SNR";
case Mpeg2SpatialProfile: return "MPEG-2 Spatial";
case Mpeg2HighProfile: return "MPEG-2 High";
case Mpeg2422Profile: return "MPEG-2 422";
default: return "MPEG-2 Video";
}
case GeneralMediaFormat::Mpeg4Video:
switch(sub) {
case Mpeg4Sp: return "MPEG-4 SP";
case Mpeg4Asp: return "H.263";
case Mpeg4Avc: return "H.264";
case Mpeg4AvcParams: return "H.264 params";
case Mpeg4MsV3: return "MPEG-4 MS V3";
default: return "MPEG-4 Visual";
}
case GeneralMediaFormat::Mpc: return "MPC";
case GeneralMediaFormat::Pcm:
switch(sub) {
case PcmIntBe: return "PCM (int, BE)";
case PcmIntLe: return "PCM (int, LE)";
case PcmFloatIeee: return "PCM IEEE";
default: return "PCM";
}
case GeneralMediaFormat::Png: return "PNG";
case GeneralMediaFormat::ProRes: return "ProRes";
case GeneralMediaFormat::Qcelp: return "QCELP";
case GeneralMediaFormat::QuicktimeAudio: return "Quicktime Audio";
case GeneralMediaFormat::QuicktimeVideo: return "Quicktime Video";
case GeneralMediaFormat::RealAudio: return "Real Audio";
case GeneralMediaFormat::RealVideo: return "Real Video";
case GeneralMediaFormat::Sa0c: return "SAOC";
case GeneralMediaFormat::Smv: return "SMV";
case GeneralMediaFormat::StreamingTextStream: return "Streaming Text Stream";
case GeneralMediaFormat::SynthesizedTextureStream: return "Synthesized Texture Stream";
case GeneralMediaFormat::Systems:
switch(sub) {
case 2: return "Systems v2";
default: return "Systems";
}
case GeneralMediaFormat::TextSubtitle:
switch(sub) {
case SubFormats::TextSubBasicUtf8: return "UTF-8 Sub";
case SubFormats::TextSubSubtitlesFormat: return "SSA";
case SubFormats::TextSubAdvancedSubtitlesFormat: return "ASS";
case SubFormats::TextSubUniversalSubtitleFormat: return "USF";
default: return "Text subtitle";
}
case GeneralMediaFormat::Theora: return "Theora";
case GeneralMediaFormat::Tiff: return "TIFF";
case GeneralMediaFormat::Tta: return "TTA";
case GeneralMediaFormat::UncompressedVideoFrames: return "uncompressed video frames";
case GeneralMediaFormat::Vc1: return "VC-1";
case GeneralMediaFormat::VobBtn: return "VobBtn";
case GeneralMediaFormat::VobSub: return "VobSub";
case GeneralMediaFormat::Vorbis: return "Vorbis";
case GeneralMediaFormat::WavPack: return "WavPack";
default: return "";
} }
} }

View File

@ -1,61 +1,185 @@
#ifndef MEDIAFORMAT_H #ifndef MEDIAFORMAT_H
#define MEDIAFORMAT_H #define MEDIAFORMAT_H
#include <c++utilities/application/global.h>
#include <utility>
namespace Media { namespace Media {
/*! /*!
* \brief The MediaType enum specifies the type of media data (acoustic, visual, textual, ...). * \brief The MediaType enum specifies the type of media data (audio, video, text, ...).
*/ */
enum class MediaType enum class MediaType
{ {
Acoustic, Unknown,
Visual, Audio,
Textual, Video,
Hint, Text,
Unknown Hint
}; };
/*! /*!
* \brief The MediaFormat enum specifies the format of media data (PCM, MPEG-4, PNG, ...). * \brief The GeneralMediaFormat enum specifies the general format of media data (PCM, MPEG-4, PNG, ...).
*/ */
enum class MediaFormat enum class GeneralMediaFormat
{ {
Pcm, Unknown,
Mpeg1, Aac, /**< Advanced Video Coding */
Mpeg2, Ac3, /**< Dolby Digital */
MpegL1, Ac4, /**< AC-4 */
MpegL2, AdpcmAcm, /**< ADPCM ACM */
MpegL3, AfxStream, /**< AFX Stream */
Aac, Alac, /**< Apple Lossless Audio Codec */
Alac, Als, /**< ALS */
Vorbis, Bitmap, /**< Windows Bitmap */
Png, Dirac, /**< Dirac */
Jpeg, Dts, /**< DTS */
Bitmap, DtsHd, /**< DTS-HD */
Mpeg4Sp, EAc3, /**< Dolby Digital Plus */
Mpeg4Avc, Evrc, /**< EVRC */
Mpeg4Asp, Flac, /**< FLAC */
Mpeg4, FontDataStream, /**< Font Data Stream */
Gif, Gif, /**< GIF */
Tiff, Gpp2Cmf, /**< 3GPP2 Compact Multimedia Format (CMF) */
UncompressedRgb, ImaadpcmAcm, /**< IMAADPCM ACM */
AdpcmAcm, ImageSubtitle, /**< Image subtitle */
ImaadpcmAcm, InteractionStream, /**< Interaction Stream */
Ac3, Jpeg, /**< JPEG */
Ac4, OggKate, /**< Karaoke And Text Encapsulation */
Dts, MicrosoftAudioCodecManager, /**< Microsoft Audio Codec Manager (ACM) */
Flac, MicrosoftVideoCodecManager, /**< Microsoft Video Codec Manager (VCM) */
RealAudio, Mpeg1Audio, /**< MPEG-1 Audio */
RealVideo, Mpeg1Video, /**< MPEG-1 Vudio */
QuicktimeVideo, Mpeg2Audio, /**< MPEG-2 Audio */
QuicktimeAudio, Mpeg2Video, /**< MPEG-2 Vudio */
Theora, Mpeg4Video, /**< MPEG-4 */
ProRes, Mpc, /**< Musepack */
VobSub, Pcm, /**< Pulse Code Modulation */
Unknown Png, /**< PNG */
ProRes, /**< ProRes */
Qcelp, /**< QCELP */
QuicktimeAudio, /**< Quicktime Audio */
QuicktimeVideo, /**< Quicktime Video */
RealAudio, /**< Real Audio */
RealVideo, /**< Real Video */
Sa0c, /**< SAOC */
Smv, /**< SMV */
StreamingTextStream, /**< Streaming Text Stream */
SynthesizedTextureStream, /**< Synthesized Texture Stream */
Systems, /**< Systems */
TextSubtitle, /**< Text subtitle */
Theora, /**< Theora */
Tiff, /**< TIFF */
Tta, /**< The True Audio lessles audio compressor */
UncompressedVideoFrames, /**< uncompressed RGB */
Vc1, /**< VC-1 */
VobBtn, /**< VobBtn */
VobSub, /**< VobSub */
Vorbis, /**< Vorbis */
WavPack /**< WavPack */
}; };
const char *mediaFormatName(MediaFormat mediaFormat); /*!
* \brief Encapsulates sub formats.
*
* For instance "Layer 3" is a sub format of MPEG-1 audio.
*/
namespace SubFormats {
enum : unsigned char {
None
};
enum Mpeg1AudioLayer : unsigned char {
Mpeg1Layer1 = 1,
Mpeg1Layer2,
Mpeg1Layer3
};
enum AacProfile : unsigned char {
AacMpeg2MainProfile = 1,
AacMpeg2LowComplexityProfile,
AacMpeg2SpectralBandReplicationProfile,
AacMpeg2ScalableSamplingRateProfile,
AacMpeg4MainProfile,
AacMpeg4LowComplexityProfile,
AacMpeg4SpectralBandReplicationProfile,
AacMpeg4ScalableSamplingRateProfile,
AacMpeg4LongTermPredictionProfile
};
enum Mpeg2VideoProfile : unsigned char {
Mpeg2SimpleProfile = 1,
Mpeg2MainProfile,
Mpeg2SnrProfile,
Mpeg2SpatialProfile,
Mpeg2HighProfile,
Mpeg2422Profile
};
enum Mpeg4VideoProfile : unsigned char {
Mpeg4Sp = 1,
Mpeg4Asp,
Mpeg4Avc,
Mpeg4AvcParams,
Mpeg4MsV3
};
enum DtsSpecifier : unsigned char {
DtsExpress = 1,
DtsLossless,
DtsHdHighResolution,
DtsHdMasterAudio,
};
enum PcmVersion : unsigned char {
PcmIntBe = 1,
PcmIntLe,
PcmFloatIeee
};
enum TextSubtitle : unsigned char {
TextSubBasicUtf8 = 1,
TextSubSubtitlesFormat,
TextSubAdvancedSubtitlesFormat,
TextSubUniversalSubtitleFormat
};
enum ImageSubtitle : unsigned char {
ImgSubBmp = 1
};
}
class LIB_EXPORT MediaFormat
{
public:
MediaFormat(GeneralMediaFormat general = GeneralMediaFormat::Unknown, unsigned char sub = 0);
const char *name() const;
const char *abbreviation() const;
operator bool() const;
GeneralMediaFormat general;
unsigned char sub;
};
/*!
* \brief Constructs a new media format.
*/
inline MediaFormat::MediaFormat(GeneralMediaFormat general, unsigned char sub) :
general(general),
sub(sub)
{}
/*!
* \brief Returns whether the media format is known.
*/
inline MediaFormat::operator bool() const
{
return general != GeneralMediaFormat::Unknown;
}
} }

View File

@ -28,6 +28,13 @@ Mp4Atom::Mp4Atom(GenericFileElement::containerType &container, uint64 startOffse
GenericFileElement<Mp4Atom>(container, startOffset) GenericFileElement<Mp4Atom>(container, startOffset)
{} {}
/*!
* \brief Constructs a new top level atom with the specified \a container at the specified \a startOffset.
*/
Mp4Atom::Mp4Atom(GenericFileElement::containerType &container, uint64 startOffset, uint64 maxSize) :
GenericFileElement<Mp4Atom>(container, startOffset, maxSize)
{}
/*! /*!
* \brief Constructs a new sub level atom with the specified \a parent at the specified \a startOffset. * \brief Constructs a new sub level atom with the specified \a parent at the specified \a startOffset.
*/ */
@ -98,7 +105,7 @@ void Mp4Atom::internalParse()
if(parent()) { if(parent()) {
sibling = new Mp4Atom(*(parent()), startOffset() + totalSize()); sibling = new Mp4Atom(*(parent()), startOffset() + totalSize());
} else { } else {
sibling = new Mp4Atom(container(), startOffset() + totalSize()); sibling = new Mp4Atom(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
} }
} }
m_nextSibling.reset(sibling); m_nextSibling.reset(sibling);

View File

@ -35,6 +35,11 @@ public:
*/ */
typedef uint32 identifierType; typedef uint32 identifierType;
/*!
* \brief The type used to store element sizes is an unsigned 64-bit integer.
*/
typedef uint64 dataSizeType;
/*! /*!
* \brief The implementation type is Mp4Atom. * \brief The implementation type is Mp4Atom.
*/ */
@ -56,6 +61,7 @@ public:
static void seekBackAndWriteAtomSize(std::ostream &stream, const std::ostream::pos_type &startOffset, bool denote64BitSize = false); static void seekBackAndWriteAtomSize(std::ostream &stream, const std::ostream::pos_type &startOffset, bool denote64BitSize = false);
protected: protected:
Mp4Atom(containerType& container, uint64 startOffset, uint64 maxSize);
Mp4Atom(implementationType &parent, uint64 startOffset); Mp4Atom(implementationType &parent, uint64 startOffset);
void internalParse(); void internalParse();

View File

@ -1,5 +1,7 @@
#include "mp4ids.h" #include "mp4ids.h"
#include "../mediaformat.h"
namespace Media { namespace Media {
/*! /*!
@ -35,15 +37,157 @@ namespace Mp4MediaTypeIds {
} }
/*! /*!
* \brief Encapsulates all supported MP4 media format IDs. * \brief Encapsulates all supported MP4 media format IDs (aka "FOURCCs").
* \sa http://wiki.multimedia.cx/?title=QuickTime_container
*/ */
namespace Mp4FormatIds { namespace Mp4FormatIds {
MediaFormat fourccToMediaFormat(uint32 fourccId)
{
switch(fourccId) {
case Mp4FormatIds::Mpeg4Video:
return GeneralMediaFormat::Mpeg4Video;
case Mp4FormatIds::Avc1:
case Mp4FormatIds::Avc2:
case Mp4FormatIds::Avc3:
case Mp4FormatIds::Avc4:
return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Avc);
case Mp4FormatIds::H263:
return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Asp);
case Mp4FormatIds::Tiff:
return GeneralMediaFormat::Tiff;
case Mp4FormatIds::Raw:
return GeneralMediaFormat::UncompressedVideoFrames;
case Mp4FormatIds::Jpeg:
return GeneralMediaFormat::Jpeg;
case Mp4FormatIds::Gif:
return GeneralMediaFormat::Gif;
case Mp4FormatIds::AdpcmAcm:
return GeneralMediaFormat::AdpcmAcm;
case Mp4FormatIds::ImaadpcmAcm:
return GeneralMediaFormat::ImaadpcmAcm;
case Mp4FormatIds::Mp3CbrOnly:
return MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer3);
case Mp4FormatIds::Mpeg4Audio:
return GeneralMediaFormat::Aac;
case Mp4FormatIds::Alac:
return GeneralMediaFormat::Alac;
case Mp4FormatIds::Ac3:
return GeneralMediaFormat::Ac3;
case Mp4FormatIds::Ac4:
return GeneralMediaFormat::Ac4;
default:
return GeneralMediaFormat::Unknown;
}
}
} }
/*! /*!
* \brief Encapsulates all supported MP4 media format configuration box IDs. * \brief Encapsulates all supported MP4 media format description extensions.
* \sa https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
*/ */
namespace Mp4FormatConfigurationIds { namespace Mp4FormatExtensionIds {
}
/*!
* \brief Encapsulates all supported MPEG-4 elementary stream object IDs.
*/
namespace Mpeg4ElementaryStreamObjectIds {
/*!
* \brief Returns the Media::MediaFormat denoted by the specified MPEG-4 stream ID.
*/
MediaFormat streamObjectTypeFormat(byte streamObjectTypeId)
{
switch(streamObjectTypeId) {
case SystemsIso144961: return GeneralMediaFormat::Systems;
case SystemsIso144961v2: return MediaFormat(GeneralMediaFormat::Systems, 2);
case InteractionStream: return GeneralMediaFormat::InteractionStream;
case AfxStream: return GeneralMediaFormat::AfxStream;
case FontDataStream: return GeneralMediaFormat::FontDataStream;
case SynthesizedTextureStream: return GeneralMediaFormat::SynthesizedTextureStream;
case StreamingTextStream: return GeneralMediaFormat::StreamingTextStream;
case Mpeg4Visual: return GeneralMediaFormat::Mpeg4Video;
case Avc: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Avc);
case ParameterSetsForAvc: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4AvcParams);
case Als: return GeneralMediaFormat::Als;
case Sa0c: return GeneralMediaFormat::Sa0c;
case Aac: return GeneralMediaFormat::Aac;
case Mpeg2VideoSimpleProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2SimpleProfile);
case Mpeg2VideoMainProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2SnrProfile);
case Mpeg2VideoSnrProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2SpatialProfile);
case Mpeg2VideoSpatialProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2HighProfile);
case Mpeg2VideoHighProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2HighProfile);
case Mpeg2Video422Profile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2SimpleProfile);
case AacMainProfile: return MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg2MainProfile);
case AacLowComplexityProfile: return MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg2LowComplexityProfile);
case AacScaleableSamplingRateProfile: return MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg2ScalableSamplingRateProfile);
case Mpeg2Audio: return GeneralMediaFormat::Mpeg2Audio;
case Mpeg1Video: return GeneralMediaFormat::Mpeg1Video;
case Mpeg1Audio: return GeneralMediaFormat::Mpeg1Audio;
case Jpeg: return GeneralMediaFormat::Jpeg;
case Png: return GeneralMediaFormat::Png;
case Evrc: case PrivateEvrc: return GeneralMediaFormat::Evrc;
case Smv: return GeneralMediaFormat::Smv;
case Gpp2Cmf: return GeneralMediaFormat::Gpp2Cmf;
case Vc1: return GeneralMediaFormat::Vc1;
case Dirac: return GeneralMediaFormat::Dirac;
case Ac3: case PrivateAc3: return GeneralMediaFormat::Ac3;
case EAc3: return GeneralMediaFormat::EAc3;
case Dts: case PrivateDts: return GeneralMediaFormat::Dts;
case DtsHdHighResolution: return MediaFormat(GeneralMediaFormat::DtsHd, SubFormats::DtsHdHighResolution);
case DtsHdMasterAudio: return MediaFormat(GeneralMediaFormat::DtsHd, SubFormats::DtsHdMasterAudio);
case DtsHdExpress: return MediaFormat(GeneralMediaFormat::DtsHd, SubFormats::DtsExpress);
case PrivateOgg: case PrivateOgg2: return GeneralMediaFormat::Vorbis;
case PrivateQcelp: return GeneralMediaFormat::Qcelp;
default: return MediaFormat();
}
}
}
/*!
* \brief Encapsulates all known MPEG-4 descriptor IDs.
*/
namespace Mpeg4DescriptorIds {
}
/*!
* \brief Returns the name of the stream type denoted by the specified MPEG-4 stream type ID.
*/
namespace Mpeg4ElementaryStreamTypeIds {
/*!
* \brief Returns the name of the stream type denoted by the specified MPEG-4 stream type ID.
*/
const char *streamTypeName(byte streamTypeId)
{
switch(streamTypeId) {
case ObjectDescriptor: return "object descriptor";
case ClockReference: return "clock reference";
case SceneDescriptor: return "scene descriptor";
case Visual: return "visual";
case Audio: return "audio";
case Mpeg7: return "MPEG-7";
case Ipmps: return "IMPS";
case ObjectContentInfo: return "object content info";
case MpegJava: return "MPEG Java";
case Interaction: return "interaction";
case Ipmp: return "IPMP";
case FontData: return "font data";
case StreamingText: return "streaming text";
default: "";
}
}
}
/*!
* \brief Encapsulates all supported MPEG-4 audio object format IDs.
* \sa http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio
*/
namespace Mpeg4AudioObjectIds {
} }
} }

View File

@ -6,6 +6,8 @@
namespace Media namespace Media
{ {
class MediaFormat;
namespace Mp4AtomIds { namespace Mp4AtomIds {
enum KnownValue : uint32 { enum KnownValue : uint32 {
AvcConfiguration = 0x61766343, AvcConfiguration = 0x61766343,
@ -66,8 +68,8 @@ enum KnownValue : uint32 {
TrackExtends = 0x74726578, TrackExtends = 0x74726578,
TrackFragmentRun = 0x7472756E, TrackFragmentRun = 0x7472756E,
UserData = 0x75647461, UserData = 0x75647461,
DataEntryUrl = 0x75726C20, DataEntryUrl = 0x75726C20,
DataEntryUrn = 0x75726E20, DataEntryUrn = 0x75726E20,
VideoMediaHeader = 0x766D6864, VideoMediaHeader = 0x766D6864,
Wide = 0x77696465 Wide = 0x77696465
}; };
@ -125,39 +127,228 @@ extern const char *cdec;
namespace Mp4MediaTypeIds { namespace Mp4MediaTypeIds {
enum KnownValue : uint32 { enum KnownValue : uint32 {
Sound = 0x736f756e, Sound = 0x736f756e, /**< Sound/Audio */
Video = 0x76696465, Video = 0x76696465, /**< Video */
Hint = 0x68696e74, Hint = 0x68696e74, /**< Hint */
Meta = 0x6d657461 Meta = 0x6d657461 /**< Meta */
}; };
} }
namespace Mp4FormatIds { namespace Mp4FormatIds {
enum KnownValue : uint32 { enum KnownValue : uint32 {
Mpeg4Visual = 0x6d703476, Cinepak = 0x63766964, /**< Cinepak */
Avc1 = 0x61766331, Mpeg4Video = 0x6d703476, /**< MPEG-4 video */
Avc2 = 0x61766332, Graphics = 0x736D6320, /**< Graphics */
Avc3 = 0x61766333, Animation = 0x726C6520, /**< Animation */
Avc4 = 0x61766334, AppleVideo = 0x72707A61, /**< Apple video */
H263 = 0x68323633, Png = 0x706E6720, /**< Portable Network Graphics */
Tiff = 0x74696666, Avc1 = 0x61766331, /**< H.264/MPEG-4 AVC video */
Jpeg = 0x6a706567, Avc2 = 0x61766332, /**< H.264/MPEG-4 AVC video */
Raw = 0x72617720, Avc3 = 0x61766333, /**< H.264/MPEG-4 AVC video */
Gif = 0x67696620, Avc4 = 0x61766334, /**< H.264/MPEG-4 AVC video */
Mp3 = 0x2e6d7033, H263 = 0x68323633, /**< H.263/MPEG-4 ASP video */
Mpeg4Audio = 0x6d703461, Tiff = 0x74696666, /**< Tagged Image File Format */
Alac = 0x616C6163, Jpeg = 0x6a706567, /**< JPEG */
Ac3 = 0x61632d33, Raw = 0x72617720, /**< Uncompressed RGB */
Ac4 = 0x61632d34, Gif = 0x67696620, /**< CompuServe Graphics Interchange Format */
AdpcmAcm = 0x6D730002, NtscDv25Video = 0x64766320, /**< NTSC DV-25 video */
ImaadpcmAcm = 0x6D730011, PalDv25Video = 0x64766370, /**< PAL DV-25 video */
Mp3CbrOnly = 0x6D730055 MotionJpegA = 0x6D6A7061, /**< Motion-JPEG (format A) */
MotionJpegB = 0x6D6A7062, /**< Motion-JPEG (format B) */
Mp3 = 0x2e6d7033, /**< MPEG-1 Layer 3 */
Mpeg4Audio = 0x6d703461, /**< MPEG-4 audio */
Mpeg4Stream = 0x6d703473, /**< MPEG-4 stream (other then video/audio) */
Alac = 0x616C6163, /**< Apple Losless Audio Codec */
Ac3 = 0x61632d33, /**< Dolby Digital */
Ac4 = 0x61632d34, /**< ? */
AdpcmAcm = 0x6D730002, /**< ? */
ImaadpcmAcm = 0x6D730011, /**< ? */
Mp3CbrOnly = 0x6D730055 /**< MPEG-1 Layer 3 (constant bitrate only) */
};
MediaFormat fourccToMediaFormat(uint32 fourccId);
}
namespace Mp4FormatExtensionIds {
enum KnownValue : uint32 {
GammaLevel = 0x67616D61, /**< A 32-bit fixed-point number indicating the gamma level at which the image was captured. The decompressor can use this value to gamma-correct at display time. */
FieldHandling = 0x6669656C, /**< Two 8-bit integers that define field handling. */
DefaultQuantizationTable = 0x6D6A7174, /**< The default quantization table for a Motion-JPEG data stream. */
DefaultHuffmanTable = 0x6D6A6874, /**< The default Huffman table for a Motion-JPEG data stream. */
Mpeg4ElementaryStreamDescriptor = 0x65736473, /**< An MPEG-4 elementary stream descriptor atom. This extension is required for MPEG-4 video. */
Mpeg4ElementaryStreamDescriptor2 = 0x6D346473, /**< Alternative if encoded to AVC stanard. */
AvcConfiguration = 0x61766343, /**< An H.264 AVCConfigurationBox. This extension is required for H.264 video as defined in ISO/IEC 14496-15. */
PixelAspectRatio = 0x70617370, /**< Pixel aspect ratio. This extension is mandatory for video formats that use non-square pixels. */
ColorParameters = 0x636F6C72, /**< An image description extension required for all uncompressed Y´CbCr video types. */
CleanAperature = 0x636C6170 /**< Spatial relationship of Y´CbCr components relative to a canonical image center. */
}; };
} }
namespace Mp4FormatConfigurationIds { namespace Mpeg4ElementaryStreamObjectIds {
enum KnownValue : uint32 { enum KnownValue : byte {
AvcC = 0x61766343 SystemsIso144961 = 0x01, /**< Systems */
SystemsIso144961v2, /**< Systems (version 2) */
InteractionStream, /**< Interaction Stream */
AfxStream = 0x05, /**< AFX Stream */
FontDataStream, /**< Font Data Stream */
SynthesizedTextureStream, /**< Synthesized Texture Stream */
StreamingTextStream, /**< Streaming Text Stream */
Mpeg4Visual = 0x20, /**< MPEG-4 Visual */
Avc, /**< Advanced Video Coding */
ParameterSetsForAvc, /**< Parameter Sets for Advanced Video Coding */
Als = 0x24, /**< ALS */
Sa0c = 0x2B, /**< SAOC */
Aac = 0x40, /**< Audio ISO/IEC 14496-3 (AAC) */
Mpeg2VideoSimpleProfile = 0x60, /**< MPEG-2 Video Simple Profile */
Mpeg2VideoMainProfile, /**< MPEG-2 Video Main Profile */
Mpeg2VideoSnrProfile, /**< MPEG-2 Video SNR Profile */
Mpeg2VideoSpatialProfile, /**< MPEG-2 Video Spatial Profile */
Mpeg2VideoHighProfile, /**< MPEG-2 Video High Profile */
Mpeg2Video422Profile, /**< MPEG-2 Video 422 Profile */
AacMainProfile, /**< Advanced Audio Coding Main Profile */
AacLowComplexityProfile, /**< Advanced Audio Coding Low Complexity Profile */
AacScaleableSamplingRateProfile, /**< Advanced Audio Coding Scaleable Sampling Rate Profile */
Mpeg2Audio, /**< MPEG-2 Audio */
Mpeg1Video, /**< MPEG-1 Video */
Mpeg1Audio, /**< MPEG-1 Audio */
Jpeg, /**< JPEG */
Png, /**< PNG */
Evrc = 0xA0, /**< EVRC */
Smv, /**< SMV */
Gpp2Cmf, /**< 3GPP2 Compact Multimedia Format (CMF) */
Vc1, /**< VC-1 */
Dirac, /**< Dirac */
Ac3, /**< AC-3 */
EAc3, /**< E-AC-3 */
Dts, /**< DTS */
DtsHdHighResolution, /**< DTS-HD High Resolution */
DtsHdMasterAudio, /**< DTS-HD Master Audio */
DtsHdExpress, /**< DTS-HD Express */
PrivateEvrc = 0xD1, /**< EVRC */
PrivateAc3 = 0xD3, /**< AC-3 */
PrivateDts, /**< DTS */
PrivateOgg = 0xDD, /**< Ogg */
PrivateOgg2, /**< Ogg */
PrivateQcelp = 0xE1 /**< QCELP */
};
MediaFormat streamObjectTypeFormat(byte streamObjectTypeId);
}
namespace Mpeg4ElementaryStreamTypeIds {
enum KnownValue : byte {
ObjectDescriptor = 0x01,
ClockReference,
SceneDescriptor,
Visual,
Audio,
Mpeg7,
Ipmps,
ObjectContentInfo,
MpegJava,
Interaction,
Ipmp,
FontData,
StreamingText
};
const char *streamTypeName(byte streamTypeId);
}
namespace Mpeg4DescriptorIds {
enum KnownValue : byte {
ObjectDescr = 0x01,
InitialObjectDescr,
ElementaryStreamDescr,
DecoderConfigDescr,
DecoderSpecificInfo,
SlConfigDescr,
ContentIdentDescr,
SupplContentIdentDescr,
IpiDescPointer,
IpmpDescPointer,
IpmpDescr,
QoSDescr,
RegistrationDescr,
EsIdInc,
EsIdRef,
Mp4I0d,
Mp40d,
IplDescrPointerRef,
ExtendedProfileLevelDescr,
ProfileLevelIndicationIndexDescr,
ContentClassificationDescr = 0x40,
KeyWordDescr,
RatingDescr,
LanguageDescr,
ShortTextualDescr,
ExpandedTextualDescr,
ContentCreatorNameDescr,
ContentCreationDateDescr,
IcicCreatorDateDescr,
SmpteCameraPositionDescr,
SegmentDescr,
MediaTimeDescr,
IpmpToolsListDescr = 0x60,
IpmpToolTag,
FlexMuxTimingDescr,
FlexMuxCodeTableDescr,
ExtSlConfigDescr,
FlexMuxIdentDescr,
DependencyPointer,
DependencyMaker,
FlexMuxChannelDescr,
UserPrivate = 0xC0
};
}
namespace Mpeg4AudioObjectIds {
enum KnownValue : byte {
Null = 0,
AacMain,
AacLc, /**< low complexity */
AacSsr, /**< scalable sample rate */
AacLtp, /**< long term prediction */
Sbr, /**< spectral band replication */
AacScalable,
TwinVq,
Celp, /**< code excited linear prediction */
Hxvc, /**< harmonic vector excitation coding */
Ttsi = 12, /**< text-to-speech interface */
MainSynthesis,
WavetableSynthesis,
GeneralMidi,
AlgorithmicSynthesisAudioEffects,
ErAacLc, /**< error resillent AAC LC */
ErAacLtp = 19,
ErAacScalable,
ErTwinVq,
ErBsac,
ErAacLd,
ErCelp,
ErHvxc,
ErHiln,
ErParametric,
Ssc,
Ps,
MpegSurround,
EscapeValue,
Layer1,
Layer2,
Layer3,
Dst,
Als, /**< audio lossless */
Sls, /**< scalable lossless */
ErAacEld, /**< enhanced low delay */
SmrSimple, /**< symbolic music representation */
SmrMain,
UsacNoSbr, /**< unified speech and audio coding */
Saoc, /**< spatial audio object coding (no SBR) */
LdMpegSurround,
Usac /**< unified speech and audio coding */
}; };
} }

View File

@ -213,22 +213,17 @@ void Mp4Tag::parse(Mp4Atom &metaAtom)
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) {
Mp4Atom *child = subAtom->firstChild();
Mp4TagField tagField; Mp4TagField tagField;
while(child) { for(Mp4Atom *child : *subAtom) {
try { try {
child->parse(); child->parse();
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));
addNotifications(context, *child);
addNotifications(context, tagField);
child = child->nextSibling();
} catch(Failure &) { } catch(Failure &) {
addNotifications(context, *child);
addNotifications(context, tagField);
break;
} }
addNotifications(context, *child);
addNotifications(context, tagField);
} }
} else { } else {
addNotification(NotificationType::Warning, "No ilst atom found (stores attached meta information).", context); addNotification(NotificationType::Warning, "No ilst atom found (stores attached meta information).", context);

View File

@ -2,6 +2,7 @@
#include "mp4container.h" #include "mp4container.h"
#include "mp4track.h" #include "mp4track.h"
#include "mp4ids.h" #include "mp4ids.h"
#include "mpeg4descriptor.h"
#include "../exceptions.h" #include "../exceptions.h"
#include "../mediaformat.h" #include "../mediaformat.h"
@ -21,6 +22,19 @@ namespace Media {
DateTime startDate = DateTime::fromDate(1904, 1, 1); DateTime startDate = DateTime::fromDate(1904, 1, 1);
uint32 sampleRateTable[] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
};
MediaFormat fmtTable[] = {
GeneralMediaFormat::Unknown,
MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg4MainProfile),
MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg4LowComplexityProfile),
MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg4ScalableSamplingRateProfile),
MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg4LongTermPredictionProfile),
MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg4SpectralBandReplicationProfile)
};
/*! /*!
* \class Media::Mp4Track * \class Media::Mp4Track
* \brief Implementation of Media::AbstractTrack for the MP4 container. * \brief Implementation of Media::AbstractTrack for the MP4 container.
@ -46,6 +60,7 @@ Mp4Track::Mp4Track(Mp4Atom &trakAtom) :
m_stcoAtom(nullptr), m_stcoAtom(nullptr),
m_stszAtom(nullptr), m_stszAtom(nullptr),
m_codecConfigAtom(nullptr), m_codecConfigAtom(nullptr),
m_esDescAtom(nullptr),
m_framesPerSample(1), m_framesPerSample(1),
m_chunkOffsetSize(4), m_chunkOffsetSize(4),
m_chunkCount(0), m_chunkCount(0),
@ -394,37 +409,28 @@ vector<uint64> Mp4Track::readChunkSizes()
/*! /*!
* \brief Reads the AVC configuration for the track. * \brief Reads the AVC configuration for the track.
* \remarks Ensure that the format is MediaFormat::Mpeg4Avc before calling. * \remarks
* - Returns an empty configuration for non-AVC tracks.
* - Notifications might be added.
*/ */
AvcConfiguration Mp4Track::readAvcConfiguration() AvcConfiguration Mp4Track::parseAvcConfiguration()
{ {
AvcConfiguration config; AvcConfiguration config;
try { if(m_codecConfigAtom) {
auto configSize = m_codecConfigAtom->dataSize(); try {
if(m_codecConfigAtom && configSize >= 5) { auto configSize = m_codecConfigAtom->dataSize();
// skip first byte (is always 1) if(m_codecConfigAtom && configSize >= 5) {
m_istream->seekg(m_codecConfigAtom->dataOffset() + 1); // skip first byte (is always 1)
// read profile, IDC level, NALU size length m_istream->seekg(m_codecConfigAtom->dataOffset() + 1);
config.profileIdc = m_reader.readByte(); // read profile, IDC level, NALU size length
config.profileCompat = m_reader.readByte(); config.profileIdc = m_reader.readByte();
config.levelIdc = m_reader.readByte(); config.profileCompat = m_reader.readByte();
config.naluSizeLength = m_reader.readByte() & 0x03; config.levelIdc = m_reader.readByte();
// read SPS infos config.naluSizeLength = m_reader.readByte() & 0x03;
if((configSize -= 5) >= 3) { // read SPS infos
byte entryCount = m_reader.readByte() & 0x0f;
uint16 entrySize;
while(entryCount && configSize) {
if((entrySize = m_reader.readUInt16BE()) <= configSize) {
// TODO: read entry
configSize -= entrySize;
} else {
throw TruncatedDataException();
}
--entryCount;
}
// read PPS infos
if((configSize -= 5) >= 3) { if((configSize -= 5) >= 3) {
entryCount = m_reader.readByte(); byte entryCount = m_reader.readByte() & 0x0f;
uint16 entrySize;
while(entryCount && configSize) { while(entryCount && configSize) {
if((entrySize = m_reader.readUInt16BE()) <= configSize) { if((entrySize = m_reader.readUInt16BE()) <= configSize) {
// TODO: read entry // TODO: read entry
@ -434,19 +440,107 @@ AvcConfiguration Mp4Track::readAvcConfiguration()
} }
--entryCount; --entryCount;
} }
// TODO: read trailer // read PPS infos
return config; if((configSize -= 5) >= 3) {
entryCount = m_reader.readByte();
while(entryCount && configSize) {
if((entrySize = m_reader.readUInt16BE()) <= configSize) {
// TODO: read entry
configSize -= entrySize;
} else {
throw TruncatedDataException();
}
--entryCount;
}
// TODO: read trailer
return config;
}
} }
} }
throw TruncatedDataException();
} catch (TruncatedDataException &) {
addNotification(NotificationType::Critical, "AVC configuration is truncated.", "parsing AVC configuration");
} }
throw TruncatedDataException();
} catch (TruncatedDataException &) {
addNotification(NotificationType::Critical, "AVC configuration is truncated.", "parsing AVC configuration");
} }
return config; return config;
} }
/*! /*!
* \brief Reads the MPEG-4 elementary stream descriptor for the track.
* \remarks
* - Notifications might be added.
* \sa mpeg4ElementaryStreamInfo()
*/
void Mp4Track::parseMpeg4ElementaryStreamInfo()
{
static const string context("parsing MPEG-4 elementary stream descriptor");
if(m_esDescAtom) {
if(m_esDescAtom->dataSize() >= 12) {
m_istream->seekg(m_esDescAtom->dataOffset());
// read version/flags
if(m_reader.readUInt32BE() != 0) {
addNotification(NotificationType::Warning, "Unknown version/flags.", context);
}
// read extended descriptor
Mpeg4Descriptor esDesc(m_esDescAtom->container(), m_istream->tellg(), m_esDescAtom->dataSize() - 4);
try {
esDesc.parse();
// check ID
if(esDesc.id() != Mpeg4DescriptorIds::ElementaryStreamDescr) {
addNotification(NotificationType::Critical, "Invalid descriptor found.", context);
throw Failure();
}
// read stream info
m_istream->seekg(esDesc.dataOffset());
m_esInfo = make_unique<Mpeg4ElementaryStreamInfo>();
m_esInfo->id = m_reader.readUInt16BE();
m_esInfo->esDescFlags = m_reader.readByte();
if(m_esInfo->dependencyFlag()) {
m_esInfo->dependsOnId = m_reader.readUInt16BE();
}
if(m_esInfo->urlFlag()) {
m_esInfo->url = m_reader.readString(m_reader.readByte());
}
if(m_esInfo->ocrFlag()) {
m_esInfo->ocrId = m_reader.readUInt16BE();
}
for(Mpeg4Descriptor *esDescChild = esDesc.denoteFirstChild(static_cast<uint64>(m_istream->tellg()) - esDesc.startOffset()); esDescChild; esDescChild = esDescChild->nextSibling()) {
esDescChild->parse();
switch(esDescChild->id()) {
case Mpeg4DescriptorIds::DecoderConfigDescr:
// read decoder config descriptor
m_istream->seekg(esDescChild->dataOffset());
m_esInfo->objectTypeId = m_reader.readByte();
m_esInfo->decCfgDescFlags = m_reader.readByte();
m_esInfo->bufferSize = m_reader.readUInt24BE();
m_esInfo->maxBitrate = m_reader.readUInt32BE();
m_esInfo->averageBitrate = m_reader.readUInt32BE();
for(Mpeg4Descriptor *decCfgDescChild = esDescChild->denoteFirstChild(13); decCfgDescChild; decCfgDescChild = decCfgDescChild->nextSibling()) {
decCfgDescChild->parse();
switch(esDescChild->id()) {
case Mpeg4DescriptorIds::DecoderSpecificInfo:
// read decoder specific info
break;
}
}
break;
case Mpeg4DescriptorIds::SlConfigDescr:
// uninteresting
break;
}
}
} catch (Failure &) {
// notifications will be added in any case
}
addNotifications(esDesc);
} else {
addNotification(NotificationType::Warning, "Elementary stream descriptor atom (esds) is truncated.", context);
}
}
}
/*!
* \brief Updates the chunk offsets of the track. This is necessary when the mdat atom (which contains * \brief Updates the chunk offsets of the track. This is necessary when the mdat atom (which contains
* the actual chunk data) is moved. * the actual chunk data) is moved.
* \param oldMdatOffsets Specifies a vector holding the old offsets of the "mdat"-atoms. * \param oldMdatOffsets Specifies a vector holding the old offsets of the "mdat"-atoms.
@ -648,16 +742,16 @@ void Mp4Track::makeMedia()
writer().writeUInt32BE(Mp4AtomIds::HandlerReference); writer().writeUInt32BE(Mp4AtomIds::HandlerReference);
writer().writeUInt64BE(0); // version, flags, pre defined writer().writeUInt64BE(0); // version, flags, pre defined
switch(m_mediaType) { switch(m_mediaType) {
case MediaType::Visual: case MediaType::Video:
outputStream().write("vide", 4); outputStream().write("vide", 4);
break; break;
case MediaType::Acoustic: case MediaType::Audio:
outputStream().write("soun", 4); outputStream().write("soun", 4);
break; break;
case MediaType::Hint: case MediaType::Hint:
outputStream().write("hint", 4); outputStream().write("hint", 4);
break; break;
case MediaType::Textual: case MediaType::Text:
outputStream().write("meta", 4); outputStream().write("meta", 4);
break; break;
default: default:
@ -730,6 +824,7 @@ void Mp4Track::makeMediaInfo()
/*! /*!
* \brief Makes the sample table (stbl atom) for the track. The data is written to the assigned output stream * \brief Makes the sample table (stbl atom) for the track. The data is written to the assigned output stream
* at the current position. * at the current position.
* \remarks Not fully implemented yet.
*/ */
void Mp4Track::makeSampleTable() void Mp4Track::makeSampleTable()
{ {
@ -917,13 +1012,13 @@ void Mp4Track::internalParseHeader()
m_istream->seekg(m_hdlrAtom->startOffset() + 16); // seek to beg, skip size, name, version, flags and reserved bytes m_istream->seekg(m_hdlrAtom->startOffset() + 16); // seek to beg, skip size, name, version, flags and reserved bytes
string trackTypeStr = reader.readString(4); string trackTypeStr = reader.readString(4);
if(trackTypeStr == "soun") { if(trackTypeStr == "soun") {
m_mediaType = MediaType::Acoustic; m_mediaType = MediaType::Audio;
} else if(trackTypeStr == "vide") { } else if(trackTypeStr == "vide") {
m_mediaType = MediaType::Visual; m_mediaType = MediaType::Video;
} else if(trackTypeStr == "hint") { } else if(trackTypeStr == "hint") {
m_mediaType = MediaType::Hint; m_mediaType = MediaType::Hint;
} else if(trackTypeStr == "meta") { } else if(trackTypeStr == "meta") {
m_mediaType = MediaType::Textual; m_mediaType = MediaType::Text;
} else { } else {
m_mediaType = MediaType::Unknown; m_mediaType = MediaType::Unknown;
} }
@ -941,69 +1036,37 @@ void Mp4Track::internalParseHeader()
if((codecConfigContainerAtom = m_stsdAtom->firstChild())) { if((codecConfigContainerAtom = m_stsdAtom->firstChild())) {
try { try {
codecConfigContainerAtom->parse(); codecConfigContainerAtom->parse();
switch(codecConfigContainerAtom->id()) { // parse FOURCC
case Mp4FormatIds::Mpeg4Visual: m_formatId = interpretIntegerAsString<uint32>(codecConfigContainerAtom->id());
m_format = MediaFormat::Mpeg4; m_format = Mp4FormatIds::fourccToMediaFormat(codecConfigContainerAtom->id());
break; // parse AVC configuration
case Mp4FormatIds::Avc1: m_codecConfigAtom = codecConfigContainerAtom->childById(Mp4AtomIds::AvcConfiguration);
case Mp4FormatIds::Avc2: // parse MPEG-4 elementary stream descriptor
case Mp4FormatIds::Avc3: m_esDescAtom = codecConfigContainerAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor);
case Mp4FormatIds::Avc4: if(!m_esDescAtom) {
m_format = MediaFormat::Mpeg4Avc; m_esDescAtom = codecConfigContainerAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor2);
m_codecConfigAtom = codecConfigContainerAtom->childById(Mp4AtomIds::AvcConfiguration); }
break; try {
case Mp4FormatIds::H263: parseMpeg4ElementaryStreamInfo();
m_format = MediaFormat::Mpeg4Asp; if(m_esInfo) {
break; auto mediaFormat = Mpeg4ElementaryStreamObjectIds::streamObjectTypeFormat(m_esInfo->objectTypeId);
case Mp4FormatIds::Tiff: if(mediaFormat) {
m_format = MediaFormat::Tiff; m_format = mediaFormat;
break; }
case Mp4FormatIds::Raw: }
m_format = MediaFormat::UncompressedRgb; } catch(Failure &) {
break;
case Mp4FormatIds::Jpeg:
m_format = MediaFormat::Jpeg;
break;
case Mp4FormatIds::Gif:
m_format = MediaFormat::Gif;
break;
case Mp4FormatIds::AdpcmAcm:
m_format = MediaFormat::AdpcmAcm;
break;
case Mp4FormatIds::ImaadpcmAcm:
m_format = MediaFormat::ImaadpcmAcm;
break;
case Mp4FormatIds::Mp3CbrOnly:
m_format = MediaFormat::MpegL3;
break;
case Mp4FormatIds::Mpeg4Audio:
m_format = MediaFormat::Aac;
break;
case Mp4FormatIds::Alac:
m_format = MediaFormat::Alac;
break;
case Mp4FormatIds::Ac3:
m_format = MediaFormat::Ac3;
break;
case Mp4FormatIds::Ac4:
m_format = MediaFormat::Ac4;
break;
default:
// format id is unknown
m_format = MediaFormat::Unknown;
m_formatId = interpretIntegerAsString<uint32>(codecConfigContainerAtom->id());
} }
// seek to start offset of additional atom and skip reserved bytes and data reference index // seek to start offset of additional atom and skip reserved bytes and data reference index
m_istream->seekg(codecConfigContainerAtom->startOffset() + 8 + 6 + 2); m_istream->seekg(codecConfigContainerAtom->startOffset() + 8 + 6 + 2);
switch(m_mediaType) { switch(m_mediaType) {
case MediaType::Acoustic: case MediaType::Audio:
m_istream->seekg(8, ios_base::cur); // skip reserved bytes m_istream->seekg(8, ios_base::cur); // skip reserved bytes
m_channelCount = reader.readUInt16BE(); m_channelCount = reader.readUInt16BE();
m_bitsPerSample = reader.readUInt16BE(); m_bitsPerSample = reader.readUInt16BE();
m_istream->seekg(4, ios_base::cur); // skip reserved bytes m_istream->seekg(4, ios_base::cur); // skip reserved bytes
m_samplesPerSecond = reader.readUInt32BE() >> 16; m_samplesPerSecond = reader.readUInt32BE() >> 16;
break; break;
case MediaType::Visual: case MediaType::Video:
m_istream->seekg(16, ios_base::cur); // skip reserved bytes m_istream->seekg(16, ios_base::cur); // skip reserved bytes
m_pixelSize.setWidth(reader.readUInt16BE()); m_pixelSize.setWidth(reader.readUInt16BE());
m_pixelSize.setHeight(reader.readUInt16BE()); m_pixelSize.setHeight(reader.readUInt16BE());

View File

@ -6,12 +6,79 @@
#include "../abstracttrack.h" #include "../abstracttrack.h"
#include <vector> #include <vector>
#include <memory>
namespace Media namespace Media
{ {
class Mp4Atom; class Mp4Atom;
class LIB_EXPORT Mpeg4ElementaryStreamInfo
{
public:
Mpeg4ElementaryStreamInfo();
uint16 id;
byte esDescFlags;
uint16 dependsOnId;
std::string url;
uint16 ocrId;
byte objectTypeId;
byte decCfgDescFlags;
uint32 bufferSize;
uint32 maxBitrate;
uint32 averageBitrate;
bool dependencyFlag() const;
bool urlFlag() const;
bool ocrFlag() const;
byte priority() const;
byte streamTypeId() const;
bool upstream() const;
};
inline Mpeg4ElementaryStreamInfo::Mpeg4ElementaryStreamInfo() :
id(0),
esDescFlags(0),
dependsOnId(0),
ocrId(0),
objectTypeId(0),
decCfgDescFlags(0),
bufferSize(0),
maxBitrate(0),
averageBitrate(0)
{}
inline bool Mpeg4ElementaryStreamInfo::dependencyFlag() const
{
return esDescFlags & 0x80;
}
inline bool Mpeg4ElementaryStreamInfo::urlFlag() const
{
return esDescFlags & 0x40;
}
inline bool Mpeg4ElementaryStreamInfo::ocrFlag() const
{
return esDescFlags & 0x20;
}
inline byte Mpeg4ElementaryStreamInfo::priority() const
{
return esDescFlags & 0x1F;
}
inline byte Mpeg4ElementaryStreamInfo::streamTypeId() const
{
return decCfgDescFlags >> 2;
}
inline bool Mpeg4ElementaryStreamInfo::upstream() const
{
return decCfgDescFlags & 0x02;
}
class LIB_EXPORT Mp4Track : public AbstractTrack class LIB_EXPORT Mp4Track : public AbstractTrack
{ {
public: public:
@ -25,10 +92,13 @@ public:
unsigned int chunkOffsetSize() const; unsigned int chunkOffsetSize() const;
uint32 chunkCount() const; uint32 chunkCount() const;
uint32 sampleToChunkEntryCount() const; uint32 sampleToChunkEntryCount() const;
const Mpeg4ElementaryStreamInfo *mpeg4ElementaryStreamInfo() const;
std::vector<uint64> readChunkOffsets(); std::vector<uint64> readChunkOffsets();
std::vector<std::tuple<uint32, uint32, uint32> > readSampleToChunkTable(); std::vector<std::tuple<uint32, uint32, uint32> > readSampleToChunkTable();
std::vector<uint64> readChunkSizes(); std::vector<uint64> readChunkSizes();
AvcConfiguration readAvcConfiguration(); AvcConfiguration parseAvcConfiguration();
bool hasMpeg4ElementaryStreamDesc() const;
void parseMpeg4ElementaryStreamInfo();
void updateChunkOffsets(const std::vector<int64> &oldMdatOffsets, const std::vector<int64> &newMdatOffsets); void updateChunkOffsets(const std::vector<int64> &oldMdatOffsets, const std::vector<int64> &newMdatOffsets);
void updateChunkOffset(uint32 chunkIndex, uint64 offset); void updateChunkOffset(uint32 chunkIndex, uint64 offset);
void makeTrack(); void makeTrack();
@ -56,11 +126,13 @@ private:
Mp4Atom *m_stcoAtom; Mp4Atom *m_stcoAtom;
Mp4Atom *m_stszAtom; Mp4Atom *m_stszAtom;
Mp4Atom *m_codecConfigAtom; Mp4Atom *m_codecConfigAtom;
Mp4Atom *m_esDescAtom;
uint16 m_framesPerSample; uint16 m_framesPerSample;
std::vector<uint32> m_sampleSizes; std::vector<uint32> m_sampleSizes;
unsigned int m_chunkOffsetSize; unsigned int m_chunkOffsetSize;
uint32 m_chunkCount; uint32 m_chunkCount;
uint32 m_sampleToChunkEntryCount; uint32 m_sampleToChunkEntryCount;
std::unique_ptr<Mpeg4ElementaryStreamInfo> m_esInfo;
}; };
/*! /*!
@ -109,6 +181,31 @@ inline uint32 Mp4Track::sampleToChunkEntryCount() const
return m_sampleToChunkEntryCount; return m_sampleToChunkEntryCount;
} }
/*!
* \brief Returns information about the MPEG-4 elementary stream.
* \remarks
* - The Mp4Track::readMpeg4ElementaryStreamInfo() method must be called before
* to parse the information. This is done when parsing the track.
* - The information is only available, if the track has an MPEG-4 elementary stream
* descriptor atom.
* - The track keeps ownership over the returned object.
* \sa
* - readMpeg4ElementaryStreamInfo()
* - hasMpeg4ElementaryStreamDesc()
*/
inline const Mpeg4ElementaryStreamInfo *Mp4Track::mpeg4ElementaryStreamInfo() const
{
return m_esInfo.get();
}
/*!
* \brief Returns whether the track has an MPEG-4 elementary stream descriptor atom.
*/
inline bool Mp4Track::hasMpeg4ElementaryStreamDesc() const
{
return m_esDescAtom != nullptr;
}
} }
#endif // MP4TRACK_H #endif // MP4TRACK_H

View File

@ -1,7 +1,88 @@
#include "mpeg4streamdescriptor.h" #include "mpeg4descriptor.h"
#include "mp4container.h"
Mpeg4StreamDescriptor::Mpeg4StreamDescriptor() #include "mp4ids.h"
#include <c++utilities/io/binaryreader.h>
#include <c++utilities/conversion/stringconversion.h>
using namespace std;
using namespace ConversionUtilities;
namespace Media {
/*!
* \class Media::Mpeg4Descriptor
* \brief The Mpeg4Descriptor class helps to parse MPEG-4 descriptors.
*/
/*!
* \brief Constructs a new top level descriptor with the specified \a container at the specified \a startOffset
* and with the specified \a maxSize.
*/
Mpeg4Descriptor::Mpeg4Descriptor(containerType &container, uint64 startOffset, uint64 maxSize) :
GenericFileElement<Mpeg4Descriptor>(container, startOffset, maxSize)
{}
/*!
* \brief Constructs a new sub level descriptor with the specified \a parent at the specified \a startOffset.
*/
Mpeg4Descriptor::Mpeg4Descriptor(implementationType &parent, uint64 startOffset) :
GenericFileElement<Mpeg4Descriptor>(parent, startOffset)
{}
/*!
* \brief Returns the parsing context.
*/
string Mpeg4Descriptor::parsingContext() const
{ {
return "parsing " + idToString() + " descriptor at " + numberToString(startOffset());
} }
/*!
* \brief Converts the specified atom \a ID to a printable string.
*/
std::string Mpeg4Descriptor::idToString() const
{
return "0x" + ConversionUtilities::numberToString(id(), 16);
}
/*!
* \brief Parses the MPEG-4 descriptor.
* \remarks Does not detect the first child.
*/
void Mpeg4Descriptor::internalParse()
{
invalidateStatus();
if(maxTotalSize() < 4) {
addNotification(NotificationType::Critical, "Descriptor is smaller then 4 byte and hence invalid. The maximum size within the encloding element is " + numberToString(maxTotalSize()) + ".", "parsing MPEG-4 descriptor");
throw TruncatedDataException();
}
stream().seekg(startOffset());
// read ID
m_idLength = m_sizeLength = 1;
m_id = reader().readByte();
// read data size
byte tmp = reader().readByte() & 0x80;
m_dataSize = tmp & 0x7F;
while(tmp & 0x80) {
m_dataSize = (m_dataSize << 7) | ((tmp = reader().readByte()) & 0x7F);
++m_sizeLength;
}
// check whether the denoted data size exceeds the available data size
if(maxTotalSize() < totalSize()) {
addNotification(NotificationType::Warning, "The descriptor seems to be truncated; unable to parse siblings of that ", parsingContext());
m_dataSize = maxTotalSize(); // using max size instead
}
m_firstChild.reset();
implementationType *sibling = nullptr;
if(totalSize() < maxTotalSize()) {
if(parent()) {
sibling = new implementationType(*(parent()), startOffset() + totalSize());
} else {
sibling = new implementationType(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
}
}
}
}

View File

@ -1,11 +1,103 @@
#ifndef MPEG4STREAMDESCRIPTOR_H #ifndef MPEG4DESCRIPTOR_H
#define MPEG4STREAMDESCRIPTOR_H #define MPEG4DESCRIPTOR_H
#include "../genericfileelement.h"
class Mpeg4StreamDescriptor #include <c++utilities/misc/memory.h>
namespace Media {
class Mp4Container;
class Mpeg4Descriptor;
/*!
* \brief Defines traits for the GenericFileElement implementation Mpeg4Descriptor.
*/
template <>
class LIB_EXPORT FileElementTraits<Mpeg4Descriptor>
{ {
public: public:
Mpeg4StreamDescriptor(); /*!
* \brief The container type used to store such elements is Mp4Container.
*/
typedef Mp4Container containerType;
/*!
* \brief The type used to store atom IDs is an unsigned 32-bit integer.
*/
typedef byte identifierType;
/*!
* \brief The type used to store element sizes is an unsigned 32-bit integer.
*/
typedef uint32 dataSizeType;
/*!
* \brief The implementation type is Mp4Atom.
*/
typedef Mpeg4Descriptor implementationType;
}; };
#endif // MPEG4STREAMDESCRIPTOR_H class LIB_EXPORT Mpeg4Descriptor : public GenericFileElement<Mpeg4Descriptor>
{
friend class GenericFileElement<Mpeg4Descriptor>;
public:
Mpeg4Descriptor(containerType& container, uint64 startOffset, uint64 maxSize);
std::string idToString() const;
bool isParent() const;
bool isPadding() const;
uint64 firstChildOffset() const;
implementationType *denoteFirstChild(uint32 offset);
protected:
Mpeg4Descriptor(implementationType &parent, uint64 startOffset);
void internalParse();
private:
std::string parsingContext() const;
};
/*!
* \brief Returns an indication whether the descriptor contains sub descriptors.
*
* \remarks Returns true if a first child has been denoted (via denoteFirstChild()).
*/
inline bool Mpeg4Descriptor::isParent() const
{
return m_firstChild != nullptr;
}
/*!
* \brief Returns always false for MPEG-4 descriptors.
*/
inline bool Mpeg4Descriptor::isPadding() const
{
return false;
}
/*!
* \brief Returns the offset of the first child (relative to the start offset of this descriptor).
*
* \remarks The first child must be denoted (via denoteFirstChild()).
*/
inline uint64 Mpeg4Descriptor::firstChildOffset() const
{
return firstChild() ? firstChild()->startOffset() - startOffset() : 0;
}
/*!
* \brief Denotes the first child to start at the specified \a offset (relative to the start offset of this descriptor).
* \remarks A new first child is constructed. A possibly existing subtree is invalidated.
*/
inline Mpeg4Descriptor::implementationType *Mpeg4Descriptor::denoteFirstChild(uint32 relativeFirstChildOffset)
{
m_firstChild.reset(new implementationType(static_cast<implementationType &>(*this), startOffset() + relativeFirstChildOffset));
return m_firstChild.get();
}
}
#endif // MPEG4DESCRIPTOR_H

View File

@ -24,7 +24,7 @@ namespace Media {
MpegAudioFrameStream::MpegAudioFrameStream(iostream &stream, uint64 startOffset) : MpegAudioFrameStream::MpegAudioFrameStream(iostream &stream, uint64 startOffset) :
AbstractTrack(stream, startOffset) AbstractTrack(stream, startOffset)
{ {
m_mediaType = MediaType::Acoustic; m_mediaType = MediaType::Audio;
} }
/*! /*!
@ -56,19 +56,7 @@ void MpegAudioFrameStream::internalParseHeader()
MpegAudioFrame frame; MpegAudioFrame frame;
frame.parseHeader(*m_istream); frame.parseHeader(*m_istream);
m_version = frame.mpegVersion(); m_version = frame.mpegVersion();
switch(frame.layer()) { m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, frame.layer());
case 1:
m_format = MediaFormat::MpegL1;
break;
case 2:
m_format = MediaFormat::MpegL2;
break;
case 3:
m_format = MediaFormat::MpegL3;
break;
default:
m_format = MediaFormat::Unknown;
}
m_channelCount = frame.channelMode() == MpegChannelMode::SingleChannel ? 1 : 2; m_channelCount = frame.channelMode() == MpegChannelMode::SingleChannel ? 1 : 2;
m_samplesPerSecond = frame.samperate(); m_samplesPerSecond = frame.samperate();
if(frame.isXingBytesfieldPresent()) { if(frame.isXingBytesfieldPresent()) {

View File

@ -61,12 +61,12 @@ void OggStream::internalParseHeader()
if((sig & 0x00ffffffffffff00u) == 0x00766F7262697300u) { if((sig & 0x00ffffffffffff00u) == 0x00766F7262697300u) {
// Vorbis header detected // Vorbis header detected
// set Vorbis as format // set Vorbis as format
switch(m_format) { switch(m_format.general) {
case MediaFormat::Unknown: case GeneralMediaFormat::Unknown:
m_format = MediaFormat::Vorbis; m_format = GeneralMediaFormat::Vorbis;
m_mediaType = MediaType::Acoustic; m_mediaType = MediaType::Audio;
break; break;
case MediaFormat::Vorbis: case GeneralMediaFormat::Vorbis:
break; break;
default: default:
addNotification(NotificationType::Warning, "Stream format is inconsistent.", context); addNotification(NotificationType::Warning, "Stream format is inconsistent.", context);

View File

@ -226,14 +226,14 @@ const char *containerFormatAbbreviation(ContainerFormat containerFormat, MediaTy
case ContainerFormat::Lzw: return "lzw"; case ContainerFormat::Lzw: return "lzw";
case ContainerFormat::Mp4: case ContainerFormat::Mp4:
switch(mediaType) { switch(mediaType) {
case MediaType::Acoustic: case MediaType::Audio:
return "m4a"; return "m4a";
default: default:
return "mp4"; return "mp4";
} }
case ContainerFormat::Ogg: return "ogg"; case ContainerFormat::Ogg: return "ogg";
switch(mediaType) { switch(mediaType) {
case MediaType::Visual: case MediaType::Video:
return "ogv"; return "ogv";
default: default:
return "ogg"; return "ogg";
@ -244,7 +244,7 @@ const char *containerFormatAbbreviation(ContainerFormat containerFormat, MediaTy
case ContainerFormat::Rar: return "rar"; case ContainerFormat::Rar: return "rar";
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
switch(mediaType) { switch(mediaType) {
case MediaType::Acoustic: case MediaType::Audio:
return "mka"; return "mka";
default: default:
return "mkv"; return "mkv";
@ -393,21 +393,21 @@ const char *containerMimeType(ContainerFormat containerFormat, MediaType mediaTy
return "audio/mpeg"; return "audio/mpeg";
case ContainerFormat::Mp4: case ContainerFormat::Mp4:
switch(mediaType) { switch(mediaType) {
case MediaType::Acoustic: case MediaType::Audio:
return "audio/mp4"; return "audio/mp4";
default: default:
return "video/mp4"; return "video/mp4";
} }
case ContainerFormat::Ogg: case ContainerFormat::Ogg:
switch(mediaType) { switch(mediaType) {
case MediaType::Acoustic: case MediaType::Audio:
return "audio/ogg"; return "audio/ogg";
default: default:
return "video/ogg"; return "video/ogg";
} }
case ContainerFormat::Matroska: case ContainerFormat::Matroska:
switch(mediaType) { switch(mediaType) {
case MediaType::Acoustic: case MediaType::Audio:
return "audio/x-matroska"; return "audio/x-matroska";
default: default:
return "video/x-matroska"; return "video/x-matroska";

2
size.h
View File

@ -94,7 +94,7 @@ inline constexpr bool Size::isNull() const
inline std::string Size::toString() const inline std::string Size::toString() const
{ {
std::stringstream res; std::stringstream res;
res << "width: " << m_width << "; height: " << m_height; res << "width: " << m_width << ", height: " << m_height;
return std::string(res.str()); return std::string(res.str());
} }

View File

@ -67,7 +67,8 @@ SOURCES += \
abstractattachment.cpp \ abstractattachment.cpp \
matroska/matroskaattachment.cpp \ matroska/matroskaattachment.cpp \
mediaformat.cpp \ mediaformat.cpp \
avc/avcconfiguration.cpp avc/avcconfiguration.cpp \
mp4/mpeg4descriptor.cpp
HEADERS += \ HEADERS += \
abstractcontainer.h \ abstractcontainer.h \
@ -132,7 +133,8 @@ HEADERS += \
matroska/matroskaattachment.h \ matroska/matroskaattachment.h \
mediaformat.h \ mediaformat.h \
avc/avcconfiguration.h \ avc/avcconfiguration.h \
generictagfield.h generictagfield.h \
mp4/mpeg4descriptor.h
LIBS += -lz LIBS += -lz

View File

@ -19,7 +19,7 @@ namespace Media {
WaveAudioStream::WaveAudioStream(iostream &stream, uint64 startOffset) : WaveAudioStream::WaveAudioStream(iostream &stream, uint64 startOffset) :
AbstractTrack(stream, startOffset) AbstractTrack(stream, startOffset)
{ {
m_mediaType = MediaType::Acoustic; m_mediaType = MediaType::Audio;
} }
/*! /*!
@ -46,16 +46,16 @@ void WaveAudioStream::internalParseHeader()
if(restHeaderLen >= 16u) { if(restHeaderLen >= 16u) {
switch(m_reader.readUInt16LE()) { switch(m_reader.readUInt16LE()) {
case 0x0001u: case 0x0001u:
m_format = MediaFormat::Pcm; m_format = GeneralMediaFormat::Pcm;
break; break;
case 0x0050u: case 0x0050u:
m_format = MediaFormat::MpegL2; m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer2);
break; break;
case 0x0055u: case 0x0055u:
m_format = MediaFormat::MpegL3; m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer3);
break; break;
default: default:
m_format = MediaFormat::Unknown; m_format = GeneralMediaFormat::Unknown;
} }
m_channelCount = m_reader.readUInt16LE(); m_channelCount = m_reader.readUInt16LE();
m_samplesPerSecond = m_reader.readUInt32LE(); m_samplesPerSecond = m_reader.readUInt32LE();
@ -64,7 +64,7 @@ void WaveAudioStream::internalParseHeader()
m_bitsPerSample = m_reader.readUInt16LE(); m_bitsPerSample = m_reader.readUInt16LE();
m_bitrate = m_bitsPerSample * m_samplesPerSecond * m_channelCount; m_bitrate = m_bitsPerSample * m_samplesPerSecond * m_channelCount;
} else { } else {
m_format = MediaFormat::Unknown; m_format = GeneralMediaFormat::Unknown;
} }
if(restHeaderLen > 16u) { if(restHeaderLen > 16u) {
m_istream->seekg(m_dataOffset, ios_base::beg); m_istream->seekg(m_dataOffset, ios_base::beg);