improved media format detection; other minor improvements
This commit is contained in:
parent
221a690311
commit
c452b009ae
|
@ -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";
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ public:
|
||||||
|
|
||||||
TrackType type() const;
|
TrackType type() const;
|
||||||
|
|
||||||
|
static MediaFormat codecIdToMediaFormat(const std::string &codecId);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader();
|
void internalParseHeader();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
334
mediaformat.cpp
334
mediaformat.cpp
|
@ -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 "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
208
mediaformat.h
208
mediaformat.h
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
150
mp4/mp4ids.cpp
150
mp4/mp4ids.cpp
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
245
mp4/mp4ids.h
245
mp4/mp4ids.h
|
@ -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 */
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
245
mp4/mp4track.cpp
245
mp4/mp4track.cpp
|
@ -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());
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
2
size.h
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue