improved detection of media formats in Matroska and MP4 files
This commit is contained in:
parent
045f2bb14b
commit
8618172f81
|
@ -61,14 +61,14 @@ MediaFormat MatroskaTrack::codecIdToMediaFormat(const string &codecId)
|
|||
fmt.general = GeneralMediaFormat::Mpeg4Video;
|
||||
if(part2 == "ISO") {
|
||||
if(part3 == "SP") {
|
||||
fmt.sub = SubFormats::Mpeg4Sp;
|
||||
fmt.sub = SubFormats::Mpeg4SimpleProfile1;
|
||||
} else if(part3 == "ASP") {
|
||||
fmt.sub = SubFormats::Mpeg4Asp;
|
||||
fmt.sub = SubFormats::Mpeg4AdvancedSimpleProfile1;
|
||||
} else if(part3 == "AVC") {
|
||||
fmt.sub = SubFormats::Mpeg4Avc;
|
||||
fmt.general = GeneralMediaFormat::Avc;
|
||||
}
|
||||
} else if(part2 == "MS" && part3 == "V3") {
|
||||
fmt.sub = SubFormats::Mpeg4MsV3;
|
||||
fmt.sub = SubFormats::Mpeg4SimpleProfile1;
|
||||
}
|
||||
} else if(part1 == "V_MPEG1") {
|
||||
fmt.general = GeneralMediaFormat::Mpeg1Video;
|
||||
|
|
106
mediaformat.cpp
106
mediaformat.cpp
|
@ -41,6 +41,20 @@ const char *MediaFormat::name() const
|
|||
case GeneralMediaFormat::AfxStream: return "AFX Stream";
|
||||
case GeneralMediaFormat::Alac: return "Apple Lossless Audio Codec";
|
||||
case GeneralMediaFormat::Als: return "ALS";
|
||||
case GeneralMediaFormat::Amr: return "Adaptive Multi-Rate audio codec";
|
||||
case GeneralMediaFormat::Avc:
|
||||
switch(sub) {
|
||||
case AvcBaselineProfile: return "Advanced Video Coding Basline Profile";
|
||||
case AvcMainProfile: return "Advanced Video Coding Main Profile";
|
||||
case AvcScalableBaselineProfile: return "Advanced Video Coding Scalable Basline Profile";
|
||||
case AvcScalableHighProfile: return "Advanced Video Coding Scalable High Profile";
|
||||
case AvcExtendedProfile: return "Advanced Video Coding Extended Profile";
|
||||
case AvcHighProfile: return "Advanced Video Coding High Profile";
|
||||
case AvcHigh10Profile: return "Advanced Video Coding High 10 Profile";
|
||||
case AvcHigh422Profile: return "Advanced Video Coding High 4:2:2 Profile";
|
||||
case AvcHigh444Profile: return "Advanced Video Coding High 4:4:4 Profile";
|
||||
default: return "Advanced Video Coding";
|
||||
}
|
||||
case GeneralMediaFormat::Bitmap: return "Windows Bitmap";
|
||||
case GeneralMediaFormat::Dirac: return "Dirac";
|
||||
case GeneralMediaFormat::Dts: return "DTS";
|
||||
|
@ -62,6 +76,7 @@ const char *MediaFormat::name() const
|
|||
case GeneralMediaFormat::FontDataStream: return "Font Data Stream";
|
||||
case GeneralMediaFormat::Gif: return "GIF";
|
||||
case GeneralMediaFormat::Gpp2Cmf: return "3GPP2 Compact Multimedia Format (CMF)";
|
||||
case GeneralMediaFormat::Hevc: return "High Efficiency Video Coding";
|
||||
case GeneralMediaFormat::ImaadpcmAcm: return "IMAADPCM ACM";
|
||||
case GeneralMediaFormat::ImageSubtitle:
|
||||
switch(sub) {
|
||||
|
@ -73,6 +88,7 @@ const char *MediaFormat::name() const
|
|||
case GeneralMediaFormat::OggKate: return "Karaoke And Text Encapsulation";
|
||||
case GeneralMediaFormat::MicrosoftAudioCodecManager: return "Microsoft Audio Codec Manager";
|
||||
case GeneralMediaFormat::MicrosoftVideoCodecManager: return "Microsoft Video Codec Manager";
|
||||
case GeneralMediaFormat::DolbyMlp: return "Dolby TrueHD";
|
||||
case GeneralMediaFormat::Mpeg1Audio:
|
||||
switch(sub) {
|
||||
case Mpeg1Layer1: return "MPEG-1 Layer 1";
|
||||
|
@ -100,11 +116,65 @@ const char *MediaFormat::name() const
|
|||
}
|
||||
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";
|
||||
case Mpeg4SimpleProfile1: return "MPEG-4 Simple Profile L1";
|
||||
case Mpeg4SimpleProfile2: return "MPEG-4 Simple Profile L2";
|
||||
case Mpeg4SimpleProfile3: return "MPEG-4 Simple Profile L2";
|
||||
case Mpeg4SimpleProfile0: return "MPEG-4 Simple Profile";
|
||||
case Mpeg4SimpleScalableProfile0: return "MPEG-4 Simple Scalable Profile";
|
||||
case Mpeg4SimpleScalableProfile1: return "MPEG-4 Simple Scalable Profile L1";
|
||||
case Mpeg4SimpleScalableProfile2: return "MPEG-4 Simple Scalable Profile L2";
|
||||
case Mpeg4CoreProfile1: return "MPEG-4 Core Profile L1";
|
||||
case Mpeg4CoreProfiel2: return "MPEG-4 Core Profile L2";
|
||||
case Mpeg4MainProfile2: return "MPEG-4 Main Profile L2";
|
||||
case Mpeg4MainProfile3: return "MPEG-4 Main Profile L3";
|
||||
case Mpeg4MainProfile4: return "MPEG-4 Main Profile L4";
|
||||
case Mpeg4NBitPrifle2: return "MPEG-4 N-Bit Profile L2";
|
||||
case Mpeg4ScalableTextureProfile1: return "MPEG-4 Scalable Texture Profile L1";
|
||||
case Mpeg4SimpleFaceAnimationProfile1: return "MPEG-4 Simple Face Animation Profile L1";
|
||||
case Mpeg4SimpleFaceAnimationProfile2: return "MPEG-4 Simple Face Animation Profile L2";
|
||||
case Mpeg4SimpleFbaProfile1: return "MPEG-4 Simple FBA Profile L1";
|
||||
case Mpeg4SimpleFbaProfile2: return "MPEG-4 Simple FBA Profile L2";
|
||||
case Mpeg4BasicAnimatedTextureProfiel1: return "MPEG-4 Basic Animated Texture Profile L1";
|
||||
case Mpeg4BasicAnimatedTextureProfiel2: return "MPEG-4 Basic Animated Texture Profile L2";
|
||||
case Mpeg4AvcProfile: return "MPEG-4 Advanced Audio Coding Profile";
|
||||
case Mpeg4HybridProfile1: return "MPEG-4 Hybrid Profile L1";
|
||||
case Mpeg4HybridProfile2: return "MPEG-4 Hybrid Profile L2";
|
||||
case Mpeg4AdvancedRealTimeSimpleProfile1: return "MPEG-4 Basic Animated Texture Profile L1";
|
||||
case Mpeg4AdvancedRealTimeSimpleProfile2: return "MPEG-4 Basic Animated Texture Profile L2";
|
||||
case Mpeg4AdvancedRealTimeSimpleProfile3: return "MPEG-4 Basic Animated Texture Profile L3";
|
||||
case Mpeg4AdvancedRealTimeSimpleProfile4: return "MPEG-4 Basic Animated Texture Profile L4";
|
||||
case Mpeg4CoreScalableProfile1: return "MPEG-4 Core Scalable Profile L1";
|
||||
case Mpeg4CoreScalableProfile2: return "MPEG-4 Core Scalable Profile L2";
|
||||
case Mpeg4CoreScalableProfile3: return "MPEG-4 Core Scalable Profile L3";
|
||||
case Mpeg4AdvancedCodingEfficiencyProfile1: return "MPEG-4 Advanced Coding Efficiency Profile L1";
|
||||
case Mpeg4AdvancedCodingEfficiencyProfile2: return "MPEG-4 Advanced Coding Efficiency Profile L2";
|
||||
case Mpeg4AdvancedCodingEfficiencyProfile3: return "MPEG-4 Advanced Coding Efficiency Profile L3";
|
||||
case Mpeg4AdvancedCodingEfficiencyProfile4: return "MPEG-4 Advanced Coding Efficiency Profile L4";
|
||||
case Mpeg4AdvancedCoreProfile1: return "MPEG-4 Advanced Core Profile L1";
|
||||
case Mpeg4AdvancedCoreProfile2: return "MPEG-4 Advanced Core Profile L2";
|
||||
case Mpeg4AdvancedScalableTexture1: return "MPEG-4 Advanced Scalable Texture L1";
|
||||
case Mpeg4AdvancedScalableTexture2: return "MPEG-4 Advanced Scalable Texture L2";
|
||||
case Mpeg4SimpleStudioProfile1: return "MPEG-4 Simple Studio Profile L1";
|
||||
case Mpeg4SimpleStudioProfile2: return "MPEG-4 Simple Studio Profile L2";
|
||||
case Mpeg4SimpleStudioProfile3: return "MPEG-4 Simple Studio Profile L3";
|
||||
case Mpeg4SimpleStudioProfile4: return "MPEG-4 Simple Studio Profile L4";
|
||||
case Mpeg4CoreStudioProfile1: return "MPEG-4 Core Studio Profile L1";
|
||||
case Mpeg4CoreStudioProfile2: return "MPEG-4 Core Studio Profile L2";
|
||||
case Mpeg4CoreStudioProfile3: return "MPEG-4 Core Studio Profile L3";
|
||||
case Mpeg4CoreStudioProfile4: return "MPEG-4 Core Studio Profile L4";
|
||||
case Mpeg4AdvancedSimpleProfile0: return "MPEG-4 Advanced Simple Profile";
|
||||
case Mpeg4AdvancedSimpleProfile1: return "MPEG-4 Advanced Simple Profile L1";
|
||||
case Mpeg4AdvancedSimpleProfile2: return "MPEG-4 Advanced Simple Profile L2";
|
||||
case Mpeg4AdvancedSimpleProfile3: return "MPEG-4 Advanced Simple Profile L3";
|
||||
case Mpeg4AdvancedSimpleProfile4: return "MPEG-4 Advanced Simple Profile L4";
|
||||
case Mpeg4AdvancedSimpleProfile5: return "MPEG-4 Advanced Simple Profile L5";
|
||||
case Mpeg4AdvancedSimpleProfile3b: return "MPEG-4 Advanced Simple Profile L3b";
|
||||
case Mpeg4FineGranularityScalableProfile0: return "MPEG-4 Fine Granularity Scalable Profile";
|
||||
case Mpeg4FineGranularityScalableProfile1: return "MPEG-4 Fine Granularity Scalable Profile L1";
|
||||
case Mpeg4FineGranularityScalableProfile2: return "MPEG-4 Fine Granularity Scalable Profile L2";
|
||||
case Mpeg4FineGranularityScalableProfile3: return "MPEG-4 Fine Granularity Scalable Profile L3";
|
||||
case Mpeg4FineGranularityScalableProfile4: return "MPEG-4 Fine Granularity Scalable Profile L4";
|
||||
case Mpeg4FineGranularityScalableProfile5: return "MPEG-4 Fine Granularity Scalable Profile L5";
|
||||
default: return "MPEG-4 Visual";
|
||||
}
|
||||
case GeneralMediaFormat::Mpc: return "Musepack SV8";
|
||||
|
@ -146,6 +216,7 @@ const char *MediaFormat::name() const
|
|||
case GeneralMediaFormat::Vorbis: return "Vorbis";
|
||||
case GeneralMediaFormat::Vp8: return "VP8";
|
||||
case GeneralMediaFormat::WavPack: return "WavPack";
|
||||
case GeneralMediaFormat::WindowsMediaAudio: return "Windows Media Audio";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
@ -182,6 +253,8 @@ const char *MediaFormat::abbreviation() const
|
|||
case GeneralMediaFormat::AfxStream: return "AFX";
|
||||
case GeneralMediaFormat::Alac: return "ALAC";
|
||||
case GeneralMediaFormat::Als: return "ALS";
|
||||
case GeneralMediaFormat::Amr: return "AMR";
|
||||
case GeneralMediaFormat::Avc: return "H.264";
|
||||
case GeneralMediaFormat::Bitmap: return "BMP";
|
||||
case GeneralMediaFormat::Dirac: return "Dirac";
|
||||
case GeneralMediaFormat::Dts: return "DTS";
|
||||
|
@ -203,6 +276,7 @@ const char *MediaFormat::abbreviation() const
|
|||
case GeneralMediaFormat::FontDataStream: return "FDS";
|
||||
case GeneralMediaFormat::Gif: return "GIF";
|
||||
case GeneralMediaFormat::Gpp2Cmf: return "3GPP2 CMF";
|
||||
case GeneralMediaFormat::Hevc: return "H.265";
|
||||
case GeneralMediaFormat::ImaadpcmAcm: return "IMAADPCM ACM";
|
||||
case GeneralMediaFormat::ImageSubtitle:
|
||||
switch(sub) {
|
||||
|
@ -214,6 +288,7 @@ const char *MediaFormat::abbreviation() const
|
|||
case GeneralMediaFormat::OggKate: return "OggKate";
|
||||
case GeneralMediaFormat::MicrosoftAudioCodecManager: return "MS ACM";
|
||||
case GeneralMediaFormat::MicrosoftVideoCodecManager: return "MS VCM";
|
||||
case GeneralMediaFormat::DolbyMlp: return "Dolby TrueHD";
|
||||
case GeneralMediaFormat::Mpeg1Audio:
|
||||
switch(sub) {
|
||||
case Mpeg1Layer1: return "MP1";
|
||||
|
@ -241,11 +316,21 @@ const char *MediaFormat::abbreviation() const
|
|||
}
|
||||
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";
|
||||
case Mpeg4SimpleProfile1:
|
||||
case Mpeg4SimpleProfile2:
|
||||
case Mpeg4SimpleProfile3:
|
||||
case Mpeg4SimpleProfile0:
|
||||
return "MPEG-4 SP";
|
||||
case Mpeg4AdvancedSimpleProfile0:
|
||||
case Mpeg4AdvancedSimpleProfile1:
|
||||
case Mpeg4AdvancedSimpleProfile2:
|
||||
case Mpeg4AdvancedSimpleProfile3:
|
||||
case Mpeg4AdvancedSimpleProfile4:
|
||||
case Mpeg4AdvancedSimpleProfile5:
|
||||
case Mpeg4AdvancedSimpleProfile3b:
|
||||
return "H.263";
|
||||
case Mpeg4AvcProfile:
|
||||
return "H.264";
|
||||
default: return "MPEG-4 Visual";
|
||||
}
|
||||
case GeneralMediaFormat::Mpc: return "MPC";
|
||||
|
@ -291,6 +376,7 @@ const char *MediaFormat::abbreviation() const
|
|||
case GeneralMediaFormat::Vorbis: return "Vorbis";
|
||||
case GeneralMediaFormat::Vp8: return "VP8";
|
||||
case GeneralMediaFormat::WavPack: return "WavPack";
|
||||
case GeneralMediaFormat::WindowsMediaAudio: return "WMA";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ enum class GeneralMediaFormat
|
|||
AfxStream, /**< AFX Stream */
|
||||
Alac, /**< Apple Lossless Audio Codec */
|
||||
Als, /**< ALS */
|
||||
Amr, /** < AMR */
|
||||
Avc, /** < Advanced Video Coding */
|
||||
Bitmap, /**< Windows Bitmap */
|
||||
Dirac, /**< Dirac */
|
||||
Dts, /**< DTS */
|
||||
|
@ -42,6 +44,7 @@ enum class GeneralMediaFormat
|
|||
FontDataStream, /**< Font Data Stream */
|
||||
Gif, /**< GIF */
|
||||
Gpp2Cmf, /**< 3GPP2 Compact Multimedia Format (CMF) */
|
||||
Hevc, /**< H.265/High Efficiency Video Coding */
|
||||
ImaadpcmAcm, /**< IMAADPCM ACM */
|
||||
ImageSubtitle, /**< Image subtitle */
|
||||
InteractionStream, /**< Interaction Stream */
|
||||
|
@ -49,6 +52,7 @@ enum class GeneralMediaFormat
|
|||
OggKate, /**< Karaoke And Text Encapsulation */
|
||||
MicrosoftAudioCodecManager, /**< Microsoft Audio Codec Manager (ACM) */
|
||||
MicrosoftVideoCodecManager, /**< Microsoft Video Codec Manager (VCM) */
|
||||
DolbyMlp, /** < Dolby MLP */
|
||||
Mpeg1Audio, /**< MPEG-1 Audio */
|
||||
Mpeg1Video, /**< MPEG-1 Vudio */
|
||||
Mpeg2Audio, /**< MPEG-2 Audio */
|
||||
|
@ -79,7 +83,8 @@ enum class GeneralMediaFormat
|
|||
VobSub, /**< VobSub */
|
||||
Vorbis, /**< Vorbis */
|
||||
Vp8, /** < VP8 */
|
||||
WavPack /**< WavPack */
|
||||
WavPack, /**< WavPack */
|
||||
WindowsMediaAudio /**< Windows Media Audio */
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -126,11 +131,77 @@ enum Mpeg2VideoProfile : unsigned char {
|
|||
};
|
||||
|
||||
enum Mpeg4VideoProfile : unsigned char {
|
||||
Mpeg4Sp = 1,
|
||||
Mpeg4Asp,
|
||||
Mpeg4Avc,
|
||||
Mpeg4AvcParams,
|
||||
Mpeg4MsV3
|
||||
Mpeg4SimpleProfile1 = 0x01,
|
||||
Mpeg4SimpleProfile2 = 0x02,
|
||||
Mpeg4SimpleProfile3 = 0x03,
|
||||
Mpeg4SimpleProfile0 = 0x08,
|
||||
Mpeg4SimpleScalableProfile0 = 0x10,
|
||||
Mpeg4SimpleScalableProfile1 = 0x11,
|
||||
Mpeg4SimpleScalableProfile2 = 0x12,
|
||||
Mpeg4CoreProfile1 = 0x21,
|
||||
Mpeg4CoreProfiel2 = 0x22,
|
||||
Mpeg4MainProfile2 = 0x32,
|
||||
Mpeg4MainProfile3 = 0x33,
|
||||
Mpeg4MainProfile4 = 0x34,
|
||||
Mpeg4NBitPrifle2 = 0x42,
|
||||
Mpeg4ScalableTextureProfile1 = 0x51,
|
||||
Mpeg4SimpleFaceAnimationProfile1 = 0x61,
|
||||
Mpeg4SimpleFaceAnimationProfile2 = 0x62,
|
||||
Mpeg4SimpleFbaProfile1 = 0x63,
|
||||
Mpeg4SimpleFbaProfile2 = 0x64,
|
||||
Mpeg4BasicAnimatedTextureProfiel1 = 0x71,
|
||||
Mpeg4BasicAnimatedTextureProfiel2 = 0x72,
|
||||
Mpeg4AvcProfile = 0x7F,
|
||||
Mpeg4HybridProfile1 = 0x81,
|
||||
Mpeg4HybridProfile2 = 0x82,
|
||||
Mpeg4AdvancedRealTimeSimpleProfile1 = 0x91,
|
||||
Mpeg4AdvancedRealTimeSimpleProfile2 = 0x92,
|
||||
Mpeg4AdvancedRealTimeSimpleProfile3 = 0x93,
|
||||
Mpeg4AdvancedRealTimeSimpleProfile4 = 0x94,
|
||||
Mpeg4CoreScalableProfile1 = 0xA1,
|
||||
Mpeg4CoreScalableProfile2 = 0xA2,
|
||||
Mpeg4CoreScalableProfile3 = 0xA3,
|
||||
Mpeg4AdvancedCodingEfficiencyProfile1 = 0xB1,
|
||||
Mpeg4AdvancedCodingEfficiencyProfile2 = 0xB2,
|
||||
Mpeg4AdvancedCodingEfficiencyProfile3 = 0xB3,
|
||||
Mpeg4AdvancedCodingEfficiencyProfile4 = 0xB4,
|
||||
Mpeg4AdvancedCoreProfile1 = 0xC1,
|
||||
Mpeg4AdvancedCoreProfile2 = 0xC2,
|
||||
Mpeg4AdvancedScalableTexture1 = 0xD1,
|
||||
Mpeg4AdvancedScalableTexture2 = 0xD2,
|
||||
Mpeg4SimpleStudioProfile1 = 0xE1,
|
||||
Mpeg4SimpleStudioProfile2 = 0xE2,
|
||||
Mpeg4SimpleStudioProfile3 = 0xE3,
|
||||
Mpeg4SimpleStudioProfile4 = 0xE4,
|
||||
Mpeg4CoreStudioProfile1 = 0xE5,
|
||||
Mpeg4CoreStudioProfile2 = 0xE6,
|
||||
Mpeg4CoreStudioProfile3 = 0xE7,
|
||||
Mpeg4CoreStudioProfile4 = 0xE8,
|
||||
Mpeg4AdvancedSimpleProfile0 = 0xF0,
|
||||
Mpeg4AdvancedSimpleProfile1 = 0xF1,
|
||||
Mpeg4AdvancedSimpleProfile2 = 0xF2,
|
||||
Mpeg4AdvancedSimpleProfile3 = 0xF3,
|
||||
Mpeg4AdvancedSimpleProfile4 = 0xF4,
|
||||
Mpeg4AdvancedSimpleProfile5 = 0xF5,
|
||||
Mpeg4AdvancedSimpleProfile3b = 0xF7,
|
||||
Mpeg4FineGranularityScalableProfile0 = 0xF8,
|
||||
Mpeg4FineGranularityScalableProfile1 = 0xF9,
|
||||
Mpeg4FineGranularityScalableProfile2 = 0xFA,
|
||||
Mpeg4FineGranularityScalableProfile3 = 0xFB,
|
||||
Mpeg4FineGranularityScalableProfile4 = 0xFC,
|
||||
Mpeg4FineGranularityScalableProfile5 = 0xFD
|
||||
};
|
||||
|
||||
enum AvcProfile : unsigned char {
|
||||
AvcBaselineProfile = 0x42,
|
||||
AvcMainProfile = 0x4D,
|
||||
AvcScalableBaselineProfile = 0x53,
|
||||
AvcScalableHighProfile = 0x56,
|
||||
AvcExtendedProfile = 0x58,
|
||||
AvcHighProfile = 0x64,
|
||||
AvcHigh10Profile = 0x6E,
|
||||
AvcHigh422Profile = 0x7A,
|
||||
AvcHigh444Profile = 0x90
|
||||
};
|
||||
|
||||
enum DtsSpecifier : unsigned char {
|
||||
|
@ -221,3 +292,4 @@ inline MediaFormat::operator bool() const
|
|||
}
|
||||
|
||||
#endif // MEDIAFORMAT_H
|
||||
|
||||
|
|
|
@ -151,7 +151,11 @@ bool Mp4Atom::isParent() const
|
|||
switch(id()) {
|
||||
case Movie: case Track: case Media: case MediaInformation: case DataInformation:
|
||||
case SampleTable: case UserData: case Meta: case ItunesList: case MovieFragment:
|
||||
case TrackFragment: case MovieExtends: case DataReference:
|
||||
case TrackFragment: case MovieExtends: case DataReference: case Mp4AtomIds::AvcConfiguration:
|
||||
case FourccIds::Mpeg4Audio: case FourccIds::AmrNarrowband: case FourccIds::Amr:
|
||||
case FourccIds::Drms: case FourccIds::Alac: case FourccIds::WindowsMediaAudio:
|
||||
case FourccIds::Ac3: case FourccIds::EAc3: case FourccIds::DolbyMpl:
|
||||
case FourccIds::Dts: case FourccIds::DtsH: case FourccIds::DtsE:
|
||||
return true;
|
||||
default:
|
||||
if(parent()) {
|
||||
|
@ -188,7 +192,8 @@ bool Mp4Atom::isPadding() const
|
|||
*
|
||||
* \remarks This information is not read from the atom header. The offsets are known
|
||||
* for specific atoms.
|
||||
* \remarks This method returns zero for non-parent atoms which have no childs. *
|
||||
* \remarks This method returns zero for non-parent atoms which have no childs.
|
||||
* \remarks Childs with variable offset such as the "esds"-atom must be denoted!
|
||||
*/
|
||||
uint64 Mp4Atom::firstChildOffset() const
|
||||
{
|
||||
|
@ -196,15 +201,13 @@ uint64 Mp4Atom::firstChildOffset() const
|
|||
using namespace FourccIds;
|
||||
if(isParent()) {
|
||||
switch(id()) {
|
||||
case Meta: return headerSize() + 0x4;
|
||||
case DataReference: return headerSize() + 0x8;
|
||||
case Meta: return headerSize() + 0x4u;
|
||||
case DataReference: return headerSize() + 0x8u;
|
||||
default: return headerSize();
|
||||
}
|
||||
} else {
|
||||
switch(id()) {
|
||||
case SampleDescription: return headerSize() + 0x08u;
|
||||
case Avc1: return headerSize() + 0x4eu;
|
||||
case Mpeg4Audio: return headerSize() + 0x1cu;
|
||||
default: return 0x00u;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,16 +51,21 @@ MediaFormat fourccToMediaFormat(uint32 fourccId)
|
|||
return GeneralMediaFormat::Mpeg2Video;
|
||||
case Mpeg4Video:
|
||||
return GeneralMediaFormat::Mpeg4Video;
|
||||
case Hevc1: case Hevc2:
|
||||
return MediaFormat(GeneralMediaFormat::Hevc);
|
||||
case Avc1: case Avc2: case Avc3: case Avc4: case H264Decoder1: case H264Decoder2:
|
||||
case H264Decoder3: case H264Decoder4: case H264Decoder5: case H264Decoder6:
|
||||
return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Avc);
|
||||
case H263: case XvidDecoder1: case XvidDecoder2:
|
||||
case XvidDecoder3: case XvidDecoder4: case XvidDecoder5:
|
||||
case Divx5Decoder:
|
||||
return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Asp);
|
||||
return MediaFormat(GeneralMediaFormat::Avc);
|
||||
case Divx4Decoder1: case Divx4Decoder2: case Divx4Decoder3:
|
||||
case Divx4Decoder4: case Divx4Decoder5: case Divx4Decoder6: case Divx4Decoder7:
|
||||
return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Sp);
|
||||
case H263Quicktime: case H2633GPP: case XvidDecoder1: case XvidDecoder2:
|
||||
case XvidDecoder3: case XvidDecoder4: case XvidDecoder5: case Divx5Decoder:
|
||||
return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4AdvancedSimpleProfile0);
|
||||
case Divx3Decoder1: case Divx3Decoder2: case Divx3Decoder3: case Divx3Decoder4: case Divx3Decoder5:
|
||||
case Divx3Decoder6: case Divx3Decoder7: case Divx3Decoder8: case Divx3Decoder9: case Divx3Decoder10:
|
||||
case Divx3Decoder11: case Divx3Decoder12: case Divx3Decoder13: case Divx3Decoder14: case Divx3Decoder15:
|
||||
case Divx3Decoder16: case Divx3Decoder17:
|
||||
return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4SimpleProfile0);
|
||||
case Tiff:
|
||||
return GeneralMediaFormat::Tiff;
|
||||
case AppleTextAtsuiCodec:
|
||||
|
@ -85,6 +90,10 @@ MediaFormat fourccToMediaFormat(uint32 fourccId)
|
|||
return GeneralMediaFormat::Alac;
|
||||
case Ac3:
|
||||
return GeneralMediaFormat::Ac3;
|
||||
case EAc3:
|
||||
return GeneralMediaFormat::EAc3;
|
||||
case DolbyMpl:
|
||||
return GeneralMediaFormat::DolbyMlp;
|
||||
case Ac4:
|
||||
return GeneralMediaFormat::Ac4;
|
||||
case Rv20: case Rv30: case Rv40:
|
||||
|
@ -97,6 +106,15 @@ MediaFormat fourccToMediaFormat(uint32 fourccId)
|
|||
return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe);
|
||||
case FloatingPoint32Bit: case FloatingPoint64Bit:
|
||||
return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee);
|
||||
case Amr: case AmrNarrowband:
|
||||
return MediaFormat(GeneralMediaFormat::Amr);
|
||||
case Dts: case DtsH:
|
||||
return MediaFormat(GeneralMediaFormat::Dts);
|
||||
case DtsE:
|
||||
return MediaFormat(GeneralMediaFormat::Dts, SubFormats::DtsExpress);
|
||||
case WindowsMediaAudio: case WindowsMediaAudio7:
|
||||
case WindowsMediaAudio9Professional: case WindowsMediaAudio9Standard:
|
||||
return MediaFormat(GeneralMediaFormat::WindowsMediaAudio);
|
||||
// TODO: map more FOURCCs
|
||||
default:
|
||||
return GeneralMediaFormat::Unknown;
|
||||
|
@ -131,8 +149,8 @@ MediaFormat streamObjectTypeFormat(byte streamObjectTypeId)
|
|||
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 Avc: return GeneralMediaFormat::Avc;
|
||||
case ParameterSetsForAvc: return GeneralMediaFormat::Avc;
|
||||
case Als: return GeneralMediaFormat::Als;
|
||||
case Sa0c: return GeneralMediaFormat::Sa0c;
|
||||
case Aac: return MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg4LowComplexityProfile);
|
||||
|
@ -262,4 +280,16 @@ LIB_EXPORT MediaFormat idToMediaFormat(byte mpeg4AudioObjectId, bool sbrPresent,
|
|||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Encapsulates MPEG-4 video (14496-2) codes.
|
||||
*/
|
||||
namespace Mpeg4VideoCodes {
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Encapsulates MPEG-2 video codes.
|
||||
*/
|
||||
namespace Mpeg2VideoCodes {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
48
mp4/mp4ids.h
48
mp4/mp4ids.h
|
@ -146,6 +146,7 @@ enum KnownValue : uint32 {
|
|||
Alaw21 = 0x616C6177,
|
||||
AlphaCompositor = 0x626C6E64,
|
||||
AlphaGain = 0x6761696E,
|
||||
Amr = 0x73617762,
|
||||
AmrNarrowband = 0x73616D72,
|
||||
Animation = 0x726C6520, /**< Animation */
|
||||
Appl1 = 0x6476690,
|
||||
|
@ -252,11 +253,16 @@ enum KnownValue : uint32 {
|
|||
Divx4Decoder6 = 0x6D347332,
|
||||
Divx4Decoder7 = 0x6D703473,
|
||||
Divx5Decoder = 0x44583530,
|
||||
Drm = 0x64726D73,
|
||||
Drms = 0x64726D73,
|
||||
Drmi = 0x64726D69,
|
||||
Dts = 0x6474736C,
|
||||
DtsH = 0x64747368,
|
||||
DtsE = 0x64747365,
|
||||
Dvca = 0x64766361,
|
||||
DvcPro501 = 0x64763570,
|
||||
DvcPro502 = 0x6476356E,
|
||||
DvcProPal = 0x64767070,
|
||||
EAc3 = 0x65632D33,
|
||||
EdgeDetection = 0x65646765,
|
||||
Emboss = 0x656D6273,
|
||||
Explode = 0x78706C6F,
|
||||
|
@ -271,7 +277,8 @@ enum KnownValue : uint32 {
|
|||
Glass = 0x676C6173,
|
||||
GradientWipe = 0x6D617474,
|
||||
Graphics = 0x736D6320, /**< Graphics */
|
||||
H263 = 0x68323633, /**< H.263/MPEG-4 ASP video */
|
||||
H263Quicktime = 0x68323633, /**< H.263/MPEG-4 ASP video (Quicktime) */
|
||||
H2633GPP = 0x73323633, /**< H.263 (3GPP format) */
|
||||
H264Decoder1 = 0x44415643,
|
||||
H264Decoder2 = 0x48323634,
|
||||
H264Decoder3 = 0x56535348,
|
||||
|
@ -279,6 +286,8 @@ enum KnownValue : uint32 {
|
|||
H264Decoder5 = 0x68323634,
|
||||
H264Decoder6 = 0x78323634,
|
||||
Hdv3 = 0x68647633,
|
||||
Hevc1 = 0x68766331, /**< H.265/High Efficiency Video Coding */
|
||||
Hevc2 = 0x68657631, /**< H.265/High Efficiency Video Coding */
|
||||
HslBalance = 0x68736C62,
|
||||
Ima4 = 0x696D6134,
|
||||
Ima41 = 0x696D6134,
|
||||
|
@ -303,6 +312,7 @@ enum KnownValue : uint32 {
|
|||
Mace31 = 0x4D414333,
|
||||
Mace61 = 0x4D414336,
|
||||
MatrixWipe = 0x736D7034,
|
||||
DolbyMpl = 0x6D6C7061,
|
||||
MotionJpegA = 0x6D6A7061, /**< Motion-JPEG (format A) */
|
||||
MotionJpegB = 0x6D6A7062, /**< Motion-JPEG (format B) */
|
||||
Mp3 = 0x2e6d7033, /**< MPEG-1 Layer 3 */
|
||||
|
@ -366,6 +376,7 @@ enum KnownValue : uint32 {
|
|||
Ulaw21 = 0x756C6177,
|
||||
VcmImageCodec = 0x4D6A7067,
|
||||
Vdva = 0x76647661,
|
||||
WindowsMediaAudio = 0x6F776D61, /**< ? */
|
||||
WindowsMediaAudio7 = 0x574D4131,
|
||||
WindowsMediaAudio9Professional = 0x574D4133,
|
||||
WindowsMediaAudio9Standard = 0x574D4132,
|
||||
|
@ -579,6 +590,39 @@ LIB_EXPORT MediaFormat idToMediaFormat(byte mpeg4AudioObjectId, bool sbrPresent
|
|||
|
||||
}
|
||||
|
||||
namespace Mpeg4VideoCodes {
|
||||
enum KnownValue : byte {
|
||||
VideoObjectStart = 0x00,
|
||||
VideoObjectLayerStart = 0x20,
|
||||
VisualObjectSequenceStart = 0xB0,
|
||||
VisualObjectSequendeEnd = 0xB1,
|
||||
UserDataStart = 0xB2,
|
||||
GroupOfVopStart = 0xB3,
|
||||
VideoSessionError = 0xB4,
|
||||
VisualObjectStart = 0xB5,
|
||||
VopStart = 0xB6,
|
||||
FbaObjectStart = 0xBA,
|
||||
FbaObjectPlaneStart = 0xBB,
|
||||
MeshObjectStart = 0xBC,
|
||||
MeshObjectPlaneStart = 0xBD,
|
||||
StillTextureObjectStart = 0xBE,
|
||||
TextureSpatialLayerStart = 0xBF,
|
||||
TextureSnrLayerStart = 0xC0,
|
||||
TextureTitleStart = 0xC1,
|
||||
TextureShapeLayerStart = 0xC2,
|
||||
StuffingStart = 0xC3
|
||||
};
|
||||
}
|
||||
|
||||
namespace Mpeg2VideoCodes {
|
||||
enum KnownValue : byte {
|
||||
Pic = 0x00,
|
||||
Seq = 0xB3,
|
||||
Ext = 0xB5,
|
||||
Gop = 0xB8
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Specifies the tag type.
|
||||
*/
|
||||
|
|
578
mp4/mp4track.cpp
578
mp4/mp4track.cpp
|
@ -61,6 +61,9 @@ Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() :
|
|||
epConfig(0)
|
||||
{}
|
||||
|
||||
Mpeg4VideoSpecificConfig::Mpeg4VideoSpecificConfig()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \class Media::Mp4Track
|
||||
* \brief Implementation of Media::AbstractTrack for the MP4 container.
|
||||
|
@ -160,140 +163,140 @@ vector<uint64> Mp4Track::readChunkOffsets()
|
|||
}
|
||||
}
|
||||
// read sample offsets of fragments
|
||||
// Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(moof, true);
|
||||
// uint64 totalDuration = 0;
|
||||
// while(moofAtom) {
|
||||
// moofAtom->parse();
|
||||
// Mp4Atom *trafAtom = moofAtom->childById(traf);
|
||||
// while(trafAtom) {
|
||||
// trafAtom->parse();
|
||||
// Mp4Atom *tfhdAtom = trafAtom->childById(tfhd);
|
||||
// while(tfhdAtom) {
|
||||
// tfhdAtom->parse();
|
||||
// uint32 calculatedDataSize = 0;
|
||||
// if(tfhdAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "tfhd atom is truncated.", context);
|
||||
// } else {
|
||||
// m_stream->seekg(tfhdAtom->dataOffset() + 1);
|
||||
// uint32 flags = reader.readUInt24();
|
||||
// if(m_id == reader.readUInt32()) { // check track ID
|
||||
// if(flags & 0x000001) { // base-data-offset present
|
||||
// calculatedDataSize += 8;
|
||||
// }
|
||||
// if(flags & 0x000002) { // sample-description-index present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000008) { // default-sample-duration present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000010) { // default-sample-size present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000020) { // default-sample-flags present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// //uint64 baseDataOffset = moofAtom->startOffset();
|
||||
// //uint32 defaultSampleDescriptionIndex = 0;
|
||||
// uint32 defaultSampleDuration = 0;
|
||||
// uint32 defaultSampleSize = 0;
|
||||
// uint32 defaultSampleFlags = 0;
|
||||
// if(tfhdAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "tfhd atom is truncated (presence of fields denoted).", context);
|
||||
// } else {
|
||||
// if(flags & 0x000001) { // base-data-offset present
|
||||
// //baseDataOffset = reader.readUInt64();
|
||||
// m_stream->seekg(8, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000002) { // sample-description-index present
|
||||
// //defaultSampleDescriptionIndex = reader.readUInt32();
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000008) { // default-sample-duration present
|
||||
// defaultSampleDuration = reader.readUInt32();
|
||||
// //m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000010) { // default-sample-size present
|
||||
// defaultSampleSize = reader.readUInt32();
|
||||
// }
|
||||
// if(flags & 0x000020) { // default-sample-flags present
|
||||
// defaultSampleFlags = reader.readUInt32();
|
||||
// //m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// }
|
||||
// Mp4Atom *trunAtom = trafAtom->childById(trun);
|
||||
// while(trunAtom) {
|
||||
// uint32 calculatedDataSize = 8;
|
||||
// if(trunAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "trun atom is truncated.", context);
|
||||
// } else {
|
||||
// m_stream->seekg(trunAtom->dataOffset() + 1);
|
||||
// uint32 flags = reader.readUInt24();
|
||||
// uint32 sampleCount = reader.readUInt32();
|
||||
// m_sampleCount += sampleCount;
|
||||
// if(flags & 0x000001) { // data offset present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000004) { // first-sample-flags present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// uint32 entrySize = 0;
|
||||
// if(flags & 0x000100) { // sample-duration present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// if(flags & 0x000200) { // sample-size present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// if(flags & 0x000400) { // sample-flags present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// if(flags & 0x000800) { // sample-composition-time-offsets present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// calculatedDataSize += entrySize * sampleCount;
|
||||
// if(trunAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "trun atom is truncated (presence of fields denoted).", context);
|
||||
// } else {
|
||||
// if(flags & 0x000001) { // data offset present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// //int32 dataOffset = reader.readInt32();
|
||||
// }
|
||||
// if(flags & 0x000004) { // first-sample-flags present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// for(uint32 i = 0; i < sampleCount; ++i) {
|
||||
// if(flags & 0x000100) { // sample-duration present
|
||||
// totalDuration += reader.readUInt32();
|
||||
// } else {
|
||||
// totalDuration += defaultSampleDuration;
|
||||
// }
|
||||
// if(flags & 0x000200) { // sample-size present
|
||||
// m_sampleSizes.push_back(reader.readUInt32());
|
||||
// m_size += m_sampleSizes.back();
|
||||
// } else {
|
||||
// m_size += defaultSampleSize;
|
||||
// }
|
||||
// if(flags & 0x000400) { // sample-flags present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000800) { // sample-composition-time-offsets present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// trunAtom = trunAtom->siblingById(trun, false);
|
||||
// }
|
||||
// if(m_sampleSizes.empty() && defaultSampleSize) {
|
||||
// m_sampleSizes.push_back(defaultSampleSize);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// tfhdAtom = tfhdAtom->siblingById(tfhd, false);
|
||||
// }
|
||||
// trafAtom = trafAtom->siblingById(traf, false);
|
||||
// }
|
||||
// moofAtom = moofAtom->siblingById(moof, false);
|
||||
// }
|
||||
// Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(moof, true);
|
||||
// uint64 totalDuration = 0;
|
||||
// while(moofAtom) {
|
||||
// moofAtom->parse();
|
||||
// Mp4Atom *trafAtom = moofAtom->childById(traf);
|
||||
// while(trafAtom) {
|
||||
// trafAtom->parse();
|
||||
// Mp4Atom *tfhdAtom = trafAtom->childById(tfhd);
|
||||
// while(tfhdAtom) {
|
||||
// tfhdAtom->parse();
|
||||
// uint32 calculatedDataSize = 0;
|
||||
// if(tfhdAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "tfhd atom is truncated.", context);
|
||||
// } else {
|
||||
// m_stream->seekg(tfhdAtom->dataOffset() + 1);
|
||||
// uint32 flags = reader.readUInt24();
|
||||
// if(m_id == reader.readUInt32()) { // check track ID
|
||||
// if(flags & 0x000001) { // base-data-offset present
|
||||
// calculatedDataSize += 8;
|
||||
// }
|
||||
// if(flags & 0x000002) { // sample-description-index present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000008) { // default-sample-duration present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000010) { // default-sample-size present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000020) { // default-sample-flags present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// //uint64 baseDataOffset = moofAtom->startOffset();
|
||||
// //uint32 defaultSampleDescriptionIndex = 0;
|
||||
// uint32 defaultSampleDuration = 0;
|
||||
// uint32 defaultSampleSize = 0;
|
||||
// uint32 defaultSampleFlags = 0;
|
||||
// if(tfhdAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "tfhd atom is truncated (presence of fields denoted).", context);
|
||||
// } else {
|
||||
// if(flags & 0x000001) { // base-data-offset present
|
||||
// //baseDataOffset = reader.readUInt64();
|
||||
// m_stream->seekg(8, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000002) { // sample-description-index present
|
||||
// //defaultSampleDescriptionIndex = reader.readUInt32();
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000008) { // default-sample-duration present
|
||||
// defaultSampleDuration = reader.readUInt32();
|
||||
// //m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000010) { // default-sample-size present
|
||||
// defaultSampleSize = reader.readUInt32();
|
||||
// }
|
||||
// if(flags & 0x000020) { // default-sample-flags present
|
||||
// defaultSampleFlags = reader.readUInt32();
|
||||
// //m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// }
|
||||
// Mp4Atom *trunAtom = trafAtom->childById(trun);
|
||||
// while(trunAtom) {
|
||||
// uint32 calculatedDataSize = 8;
|
||||
// if(trunAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "trun atom is truncated.", context);
|
||||
// } else {
|
||||
// m_stream->seekg(trunAtom->dataOffset() + 1);
|
||||
// uint32 flags = reader.readUInt24();
|
||||
// uint32 sampleCount = reader.readUInt32();
|
||||
// m_sampleCount += sampleCount;
|
||||
// if(flags & 0x000001) { // data offset present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// if(flags & 0x000004) { // first-sample-flags present
|
||||
// calculatedDataSize += 4;
|
||||
// }
|
||||
// uint32 entrySize = 0;
|
||||
// if(flags & 0x000100) { // sample-duration present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// if(flags & 0x000200) { // sample-size present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// if(flags & 0x000400) { // sample-flags present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// if(flags & 0x000800) { // sample-composition-time-offsets present
|
||||
// entrySize += 4;
|
||||
// }
|
||||
// calculatedDataSize += entrySize * sampleCount;
|
||||
// if(trunAtom->dataSize() < calculatedDataSize) {
|
||||
// addNotification(NotificationType::Critical, "trun atom is truncated (presence of fields denoted).", context);
|
||||
// } else {
|
||||
// if(flags & 0x000001) { // data offset present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// //int32 dataOffset = reader.readInt32();
|
||||
// }
|
||||
// if(flags & 0x000004) { // first-sample-flags present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// for(uint32 i = 0; i < sampleCount; ++i) {
|
||||
// if(flags & 0x000100) { // sample-duration present
|
||||
// totalDuration += reader.readUInt32();
|
||||
// } else {
|
||||
// totalDuration += defaultSampleDuration;
|
||||
// }
|
||||
// if(flags & 0x000200) { // sample-size present
|
||||
// m_sampleSizes.push_back(reader.readUInt32());
|
||||
// m_size += m_sampleSizes.back();
|
||||
// } else {
|
||||
// m_size += defaultSampleSize;
|
||||
// }
|
||||
// if(flags & 0x000400) { // sample-flags present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// if(flags & 0x000800) { // sample-composition-time-offsets present
|
||||
// m_stream->seekg(4, ios_base::cur);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// trunAtom = trunAtom->siblingById(trun, false);
|
||||
// }
|
||||
// if(m_sampleSizes.empty() && defaultSampleSize) {
|
||||
// m_sampleSizes.push_back(defaultSampleSize);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// tfhdAtom = tfhdAtom->siblingById(tfhd, false);
|
||||
// }
|
||||
// trafAtom = trafAtom->siblingById(traf, false);
|
||||
// }
|
||||
// moofAtom = moofAtom->siblingById(moof, false);
|
||||
// }
|
||||
return offsets;
|
||||
}
|
||||
|
||||
|
@ -511,7 +514,7 @@ std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamI
|
|||
// read extended descriptor
|
||||
Mpeg4Descriptor esDesc(esDescAtom->container(), m_istream->tellg(), esDescAtom->dataSize() - 4);
|
||||
try {
|
||||
esDesc.parse();
|
||||
esDesc.parse();
|
||||
// check ID
|
||||
if(esDesc.id() != Mpeg4DescriptorIds::ElementaryStreamDescr) {
|
||||
addNotification(NotificationType::Critical, "Invalid descriptor found.", context);
|
||||
|
@ -551,8 +554,12 @@ std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamI
|
|||
case Aac: case Mpeg2AacMainProfile: case Mpeg2AacLowComplexityProfile:
|
||||
case Mpeg2AacScaleableSamplingRateProfile: case Mpeg2Audio: case Mpeg1Audio:
|
||||
esInfo->audioSpecificConfig = parseAudioSpecificConfig(decCfgDescChild);
|
||||
break;
|
||||
case Mpeg4Visual:
|
||||
esInfo->videoSpecificConfig = parseVideoSpecificConfig(decCfgDescChild);
|
||||
break;
|
||||
default:
|
||||
; // TODO: covering remaining object types
|
||||
; // TODO: covering more object types
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -573,7 +580,7 @@ std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamI
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Reads the audio specific configuration for the track.
|
||||
* \brief Parses the audio specific configuration for the track.
|
||||
* \remarks
|
||||
* - Notifications might be added.
|
||||
* \sa mpeg4ElementaryStreamInfo()
|
||||
|
@ -584,7 +591,7 @@ unique_ptr<Mpeg4AudioSpecificConfig> Mp4Track::parseAudioSpecificConfig(Mpeg4Des
|
|||
using namespace Mpeg4AudioObjectIds;
|
||||
// read config into buffer and construct BitReader for bitwise reading
|
||||
m_istream->seekg(decSpecInfoDesc->dataOffset());
|
||||
cout << "audio cfg @" << decSpecInfoDesc->dataOffset() << endl;
|
||||
//cout << "audio cfg @" << decSpecInfoDesc->dataOffset() << endl;
|
||||
auto buff = make_unique<char []>(decSpecInfoDesc->dataSize());
|
||||
m_istream->read(buff.get(), decSpecInfoDesc->dataSize());
|
||||
BitReader bitReader(buff.get(), decSpecInfoDesc->dataSize());
|
||||
|
@ -670,6 +677,11 @@ unique_ptr<Mpeg4AudioSpecificConfig> Mp4Track::parseAudioSpecificConfig(Mpeg4Des
|
|||
case ErBsac: case ErAacLd: case ErCelp: case ErHvxc: case ErHiln:
|
||||
case ErParametric: case ErAacEld:
|
||||
switch(audioCfg->epConfig = bitReader.readBits<byte>(2)) {
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
bitReader.skipBits(1);
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException(); // TODO
|
||||
}
|
||||
|
@ -690,21 +702,92 @@ unique_ptr<Mpeg4AudioSpecificConfig> Mp4Track::parseAudioSpecificConfig(Mpeg4Des
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (syncExtensionType == 0x548) {
|
||||
audioCfg->psPresent = bitReader.readBits<byte>(1);
|
||||
}
|
||||
}
|
||||
} catch(ios_base::failure &) {
|
||||
if(m_istream->fail()) {
|
||||
throw; // IO error caused by input stream
|
||||
// IO error caused by input stream
|
||||
throw;
|
||||
} else {
|
||||
// IO error caused by bitReader
|
||||
addNotification(NotificationType::Critical, "Audio specific configuration is truncated.", context);
|
||||
}
|
||||
// IO error caused by bitReader
|
||||
addNotification(NotificationType::Critical, "Audio specific configuration is truncated.", context);
|
||||
} catch(NotImplementedException &) {
|
||||
addNotification(NotificationType::Information, "Not implemented for the format of audio track.", context);
|
||||
}
|
||||
return audioCfg;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
* \brief Parses the video specific configuration for the track.
|
||||
* \remarks
|
||||
* - Notifications might be added.
|
||||
* \sa mpeg4ElementaryStreamInfo()
|
||||
*/
|
||||
std::unique_ptr<Mpeg4VideoSpecificConfig> Mp4Track::parseVideoSpecificConfig(Mpeg4Descriptor *decSpecInfoDesc)
|
||||
{
|
||||
static const string context("parsing MPEG-4 video specific config from elementary stream descriptor");
|
||||
using namespace Mpeg4AudioObjectIds;
|
||||
auto videoCfg = make_unique<Mpeg4VideoSpecificConfig>();
|
||||
// seek to start
|
||||
m_istream->seekg(decSpecInfoDesc->dataOffset());
|
||||
uint64 bytesRemaining = decSpecInfoDesc->dataSize();
|
||||
if(bytesRemaining > 3 && (m_reader.readUInt24BE() == 1)) {
|
||||
bytesRemaining -= 3;
|
||||
uint32 buff1;
|
||||
while(bytesRemaining) {
|
||||
--bytesRemaining;
|
||||
switch(m_reader.readByte()) { // read start code
|
||||
case Mpeg4VideoCodes::VisualObjectSequenceStart:
|
||||
if(bytesRemaining) {
|
||||
videoCfg->profile = m_reader.readByte();
|
||||
--bytesRemaining;
|
||||
}
|
||||
break;
|
||||
case Mpeg4VideoCodes::VideoObjectLayerStart:
|
||||
|
||||
break;
|
||||
case Mpeg4VideoCodes::UserDataStart:
|
||||
buff1 = 0;
|
||||
while(bytesRemaining >= 3) {
|
||||
if((buff1 = m_reader.readUInt24BE()) != 1) {
|
||||
m_istream->seekg(-2, ios_base::cur);
|
||||
videoCfg->userData.push_back(buff1 >> 16);
|
||||
--bytesRemaining;
|
||||
} else {
|
||||
bytesRemaining -= 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(buff1 != 1 && bytesRemaining > 0) {
|
||||
videoCfg->userData += m_reader.readString(bytesRemaining);
|
||||
bytesRemaining = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
// skip stuff we're not interested in to get the start of the
|
||||
// next video object
|
||||
while(bytesRemaining >= 3) {
|
||||
if(m_reader.readUInt24BE() != 1) {
|
||||
m_istream->seekg(-2, ios_base::cur);
|
||||
--bytesRemaining;
|
||||
} else {
|
||||
bytesRemaining -= 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addNotification(NotificationType::Critical, "\"Visual Object Sequence Header\" not found.", context);
|
||||
}
|
||||
return videoCfg;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the chunk offsets of the track. This is necessary when the mdat atom (which contains
|
||||
* the actual chunk data) is moved.
|
||||
* \param oldMdatOffsets Specifies a vector holding the old offsets of the "mdat"-atoms.
|
||||
|
@ -796,8 +879,9 @@ void Mp4Track::updateChunkOffset(uint32 chunkIndex, uint64 offset)
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Makes the track entry (trak atom) for the track. The data is written to the assigned output stream
|
||||
* \brief Makes the track entry ("trak"-atom) for the track. The data is written to the assigned output stream
|
||||
* at the current position.
|
||||
* \remarks Currently the "trak"-atom from the source file is just copied to the output stream.
|
||||
*/
|
||||
void Mp4Track::makeTrack()
|
||||
{
|
||||
|
@ -1053,49 +1137,49 @@ void Mp4Track::internalParseHeader()
|
|||
static const string context("parsing MP4 track");
|
||||
using namespace Mp4AtomIds;
|
||||
if(!m_trakAtom) {
|
||||
addNotification(NotificationType::Critical, "Trak atom is null.", context);
|
||||
addNotification(NotificationType::Critical, "\"trak\"-atom is null.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
// get atoms
|
||||
try {
|
||||
if(!(m_tkhdAtom = m_trakAtom->childById(TrackHeader))) {
|
||||
addNotification(NotificationType::Critical, "No tkhd atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"tkhd\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_mdiaAtom = m_trakAtom->childById(Media))) {
|
||||
addNotification(NotificationType::Critical, "No mdia atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"mdia\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_mdhdAtom = m_mdiaAtom->childById(MediaHeader))) {
|
||||
addNotification(NotificationType::Critical, "No mdhd atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"mdhd\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_hdlrAtom = m_mdiaAtom->childById(HandlerReference))) {
|
||||
addNotification(NotificationType::Critical, "No hdlr atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"hdlr\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_minfAtom = m_mdiaAtom->childById(MediaInformation))) {
|
||||
addNotification(NotificationType::Critical, "No minf atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"minf\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_stblAtom = m_minfAtom->childById(SampleTable))) {
|
||||
addNotification(NotificationType::Critical, "No stbl atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"stbl\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_stsdAtom = m_stblAtom->childById(SampleDescription))) {
|
||||
addNotification(NotificationType::Critical, "No stsd atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"stsd\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_stcoAtom = m_stblAtom->childById(ChunkOffset)) && !(m_stcoAtom = m_stblAtom->childById(ChunkOffset64))) {
|
||||
addNotification(NotificationType::Critical, "No stco/co64 atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"stco\"/\"co64\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_stscAtom = m_stblAtom->childById(SampleToChunk))) {
|
||||
addNotification(NotificationType::Critical, "No stsc atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"stsc\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
if(!(m_stszAtom = m_stblAtom->childById(SampleSize)) && !(m_stszAtom = m_stblAtom->childById(CompactSampleSize))) {
|
||||
addNotification(NotificationType::Critical, "No stsz/stz2 atom found.", context);
|
||||
addNotification(NotificationType::Critical, "No \"stsz\"/\"stz2\"-atom found.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
} catch(Failure &) {
|
||||
|
@ -1122,7 +1206,7 @@ void Mp4Track::internalParseHeader()
|
|||
m_id = reader.readUInt32BE();
|
||||
break;
|
||||
default:
|
||||
addNotification(NotificationType::Critical, "Version of tkhd atom not supported. It will be ignored. Track ID, creation time and modification time might not be be determined.", context);
|
||||
addNotification(NotificationType::Critical, "Version of \"tkhd\"-atom not supported. It will be ignored. Track ID, creation time and modification time might not be be determined.", context);
|
||||
m_creationTime = DateTime();
|
||||
m_modificationTime = DateTime();
|
||||
m_id = 0;
|
||||
|
@ -1145,7 +1229,7 @@ void Mp4Track::internalParseHeader()
|
|||
m_duration = TimeSpan::fromSeconds(static_cast<double>(reader.readUInt64BE()) / static_cast<double>(m_timeScale));
|
||||
break;
|
||||
default:
|
||||
addNotification(NotificationType::Warning, "Version of mdhd atom not supported. It will be ignored. Creation time, modification time, time scale and duration might not be determined.", context);
|
||||
addNotification(NotificationType::Warning, "Version of \"mdhd\"-atom not supported. It will be ignored. Creation time, modification time, time scale and duration might not be determined.", context);
|
||||
m_timeScale = 0;
|
||||
m_duration = TimeSpan();
|
||||
}
|
||||
|
@ -1179,24 +1263,92 @@ void Mp4Track::internalParseHeader()
|
|||
m_istream->seekg(m_stcoAtom->dataOffset() + 4);
|
||||
m_chunkCount = reader.readUInt32BE();
|
||||
// read stsd atom
|
||||
m_istream->seekg(m_stsdAtom->startOffset() + 12); // seek to beg, skip size, name, version and flags
|
||||
m_istream->seekg(m_stsdAtom->dataOffset() + 4); // seek to beg, skip size, name, version and flags
|
||||
uint32 entryCount = reader.readUInt32BE();
|
||||
Mp4Atom *codecConfigContainerAtom;
|
||||
string::size_type firstZeroByte;
|
||||
Mp4Atom *esDescParentAtom = nullptr;
|
||||
uint16 tmp;
|
||||
if(entryCount > 0) {
|
||||
// read only first entry
|
||||
if((codecConfigContainerAtom = m_stsdAtom->firstChild())) {
|
||||
try {
|
||||
try {
|
||||
for(Mp4Atom *codecConfigContainerAtom = m_stsdAtom->firstChild(); codecConfigContainerAtom; codecConfigContainerAtom = codecConfigContainerAtom->nextSibling()) {
|
||||
codecConfigContainerAtom->parse();
|
||||
// parse FOURCC
|
||||
m_formatId = interpretIntegerAsString<uint32>(codecConfigContainerAtom->id());
|
||||
m_format = FourccIds::fourccToMediaFormat(codecConfigContainerAtom->id());
|
||||
// parse AVC configuration
|
||||
//codecConfigContainerAtom->childById(Mp4AtomIds::AvcConfiguration);
|
||||
// parse MPEG-4 elementary stream descriptor
|
||||
Mp4Atom *esDescAtom = codecConfigContainerAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor);
|
||||
// parse codecConfigContainerAtom
|
||||
m_istream->seekg(codecConfigContainerAtom->dataOffset());
|
||||
switch(codecConfigContainerAtom->id()) {
|
||||
case FourccIds::Mpeg4Audio: case FourccIds::AmrNarrowband: case FourccIds::Amr:
|
||||
case FourccIds::Drms: case FourccIds::Alac: case FourccIds::WindowsMediaAudio:
|
||||
case FourccIds::Ac3: case FourccIds::EAc3: case FourccIds::DolbyMpl:
|
||||
case FourccIds::Dts: case FourccIds::DtsH: case FourccIds::DtsE:
|
||||
m_istream->seekg(6 + 2, ios_base::cur); // skip reserved bytes, data reference index
|
||||
tmp = reader.readUInt16BE(); // read sound version
|
||||
m_istream->seekg(6, ios_base::cur);
|
||||
m_channelCount = reader.readUInt16BE();
|
||||
m_bitsPerSample = reader.readUInt16BE();
|
||||
m_istream->seekg(4, ios_base::cur); // skip reserved bytes (again)
|
||||
if(!m_sampleRate) {
|
||||
m_sampleRate = reader.readUInt32BE() >> 16;
|
||||
if(codecConfigContainerAtom->id() != FourccIds::DolbyMpl) {
|
||||
m_sampleRate >>= 16;
|
||||
}
|
||||
} else {
|
||||
m_istream->seekg(4, ios_base::cur);
|
||||
}
|
||||
if(codecConfigContainerAtom->id() != FourccIds::WindowsMediaAudio) {
|
||||
switch(tmp) {
|
||||
case 1:
|
||||
codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 16);
|
||||
break;
|
||||
case 2:
|
||||
codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 32);
|
||||
break;
|
||||
default:
|
||||
codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28);
|
||||
}
|
||||
if(!esDescParentAtom) {
|
||||
esDescParentAtom = codecConfigContainerAtom;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FourccIds::Mpeg4Video: case FourccIds::H263Quicktime: case FourccIds::H2633GPP:
|
||||
case FourccIds::Avc1: case FourccIds::Avc2: case FourccIds::Avc3: case FourccIds::Avc4:
|
||||
case FourccIds::Drmi: case FourccIds::Hevc1: case FourccIds::Hevc2:
|
||||
m_istream->seekg(6 + 2 + 16, ios_base::cur); // skip reserved bytes, data reference index, and reserved bytes (again)
|
||||
m_pixelSize.setWidth(reader.readUInt16BE());
|
||||
m_pixelSize.setHeight(reader.readUInt16BE());
|
||||
m_resolution.setWidth(static_cast<uint32>(reader.readFixed16BE()));
|
||||
m_resolution.setHeight(static_cast<uint32>(reader.readFixed16BE()));
|
||||
m_istream->seekg(4, ios_base::cur); // skip reserved bytes
|
||||
m_framesPerSample = reader.readUInt16BE();
|
||||
tmp = reader.readByte();
|
||||
m_compressorName = reader.readString(31);
|
||||
if(tmp == 0) {
|
||||
m_compressorName.clear();
|
||||
} else if(tmp < 32) {
|
||||
m_compressorName.resize(tmp);
|
||||
}
|
||||
m_depth = reader.readUInt16BE(); // 24: color without alpha
|
||||
codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 78);
|
||||
if(!esDescParentAtom) {
|
||||
esDescParentAtom = codecConfigContainerAtom;
|
||||
}
|
||||
break;
|
||||
case Mp4AtomIds::PixalAspectRatio:
|
||||
break; // TODO
|
||||
case Mp4AtomIds::CleanAperature:
|
||||
break; // TODO
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
// parse AVC configuration
|
||||
//codecConfigContainerAtom->childById(Mp4AtomIds::AvcConfiguration);
|
||||
// parse MPEG-4 elementary stream descriptor
|
||||
if(esDescParentAtom) {
|
||||
Mp4Atom *esDescAtom = esDescParentAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor);
|
||||
if(!esDescAtom) {
|
||||
esDescAtom = codecConfigContainerAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor2);
|
||||
esDescAtom = esDescParentAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor2);
|
||||
}
|
||||
if(esDescAtom) {
|
||||
try {
|
||||
|
@ -1222,6 +1374,15 @@ void Mp4Track::internalParseHeader()
|
|||
addNotification(NotificationType::Warning, "Audio specific config has invalid extension sample frequency index.", context);
|
||||
}
|
||||
}
|
||||
if(m_esInfo->videoSpecificConfig) {
|
||||
// check the video specific config for useful information
|
||||
if(m_format.general == GeneralMediaFormat::Mpeg4Video && m_esInfo->videoSpecificConfig->profile) {
|
||||
m_format.sub = m_esInfo->videoSpecificConfig->profile;
|
||||
if(!m_esInfo->videoSpecificConfig->userData.empty()) {
|
||||
m_formatId += " / " + m_esInfo->videoSpecificConfig->userData;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check the stream data for missing information
|
||||
switch(m_format.general) {
|
||||
case GeneralMediaFormat::Mpeg1Audio: case GeneralMediaFormat::Mpeg2Audio: {
|
||||
|
@ -1238,73 +1399,14 @@ void Mp4Track::internalParseHeader()
|
|||
} catch(Failure &) {
|
||||
}
|
||||
}
|
||||
// seek to start offset of additional atom and skip reserved bytes and data reference index
|
||||
m_istream->seekg(codecConfigContainerAtom->startOffset() + 8 + 6 + 2);
|
||||
switch(m_mediaType) {
|
||||
case MediaType::Audio:
|
||||
m_istream->seekg(8, ios_base::cur); // skip reserved bytes
|
||||
m_channelCount = reader.readUInt16BE();
|
||||
m_bitsPerSample = reader.readUInt16BE();
|
||||
m_istream->seekg(4, ios_base::cur); // skip reserved bytes
|
||||
if(!m_sampleRate) {
|
||||
m_sampleRate = reader.readUInt32BE() >> 16;
|
||||
} else {
|
||||
m_istream->seekg(4, ios_base::cur);
|
||||
}
|
||||
break;
|
||||
case MediaType::Video:
|
||||
m_istream->seekg(16, ios_base::cur); // skip reserved bytes
|
||||
m_pixelSize.setWidth(reader.readUInt16BE());
|
||||
m_pixelSize.setHeight(reader.readUInt16BE());
|
||||
m_resolution.setWidth(reader.readUInt32BE());
|
||||
m_resolution.setHeight(reader.readUInt32BE());
|
||||
m_istream->seekg(4, ios_base::cur); // skip reserved bytes
|
||||
m_framesPerSample = reader.readUInt16BE();
|
||||
m_compressorName = reader.readString(30);
|
||||
firstZeroByte = m_compressorName.find('\0');
|
||||
if(firstZeroByte == 0) {
|
||||
m_compressorName.clear();
|
||||
} else if(firstZeroByte != string::npos) {
|
||||
m_compressorName.resize(firstZeroByte - 1);
|
||||
}
|
||||
m_depth = reader.readUInt16BE();
|
||||
if(m_depth == 0x0018) {
|
||||
// images are in color with no alpha
|
||||
} else {
|
||||
m_depth = 0;
|
||||
}
|
||||
codecConfigContainerAtom = codecConfigContainerAtom->nextSibling();
|
||||
if(codecConfigContainerAtom) {
|
||||
while(codecConfigContainerAtom) {
|
||||
codecConfigContainerAtom->parse();
|
||||
switch(codecConfigContainerAtom->id()) {
|
||||
case Mp4AtomIds::PixalAspectRatio:
|
||||
break; // todo
|
||||
case Mp4AtomIds::CleanAperature:
|
||||
break; // todo
|
||||
default:
|
||||
;
|
||||
}
|
||||
codecConfigContainerAtom = codecConfigContainerAtom->nextSibling();
|
||||
}
|
||||
codecConfigContainerAtom = codecConfigContainerAtom->siblingById(Mp4AtomIds::Drms, true);
|
||||
if(codecConfigContainerAtom) {
|
||||
m_encrypted = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
} catch(Failure &) {
|
||||
addNotification(NotificationType::Warning, "Unable to parse child atoms of stsd atom correctly.", context);
|
||||
}
|
||||
} catch (Failure &) {
|
||||
addNotification(NotificationType::Critical, "Unable to parse child atoms of \"stsd\"-atom.", context);
|
||||
}
|
||||
}
|
||||
// read stsz atom which holds the sample size table
|
||||
m_sampleSizes.clear();
|
||||
m_size = 0;
|
||||
m_sampleCount = 0;
|
||||
m_size = m_sampleCount = 0;
|
||||
uint64 actualSampleSizeTableSize = m_stszAtom->dataSize();
|
||||
if(actualSampleSizeTableSize < 12) {
|
||||
addNotification(NotificationType::Critical, "The stsz atom is truncated. There are no sample sizes present. The size of the track can not be determined.", context);
|
||||
|
@ -1374,15 +1476,12 @@ void Mp4Track::internalParseHeader()
|
|||
}
|
||||
}
|
||||
// no sample sizes found, search for trun atoms
|
||||
Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(MovieFragment, true);
|
||||
uint64 totalDuration = 0;
|
||||
while(moofAtom) {
|
||||
for(Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(MovieFragment, true); moofAtom; moofAtom = moofAtom->siblingById(MovieFragment, false)) {
|
||||
moofAtom->parse();
|
||||
Mp4Atom *trafAtom = moofAtom->childById(TrackFragment);
|
||||
while(trafAtom) {
|
||||
for(Mp4Atom *trafAtom = moofAtom->childById(TrackFragment); trafAtom; trafAtom = trafAtom->siblingById(TrackFragment, false)) {
|
||||
trafAtom->parse();
|
||||
Mp4Atom *tfhdAtom = trafAtom->childById(TrackFragmentHeader);
|
||||
while(tfhdAtom) {
|
||||
for(Mp4Atom *tfhdAtom = trafAtom->childById(TrackFragmentHeader); tfhdAtom; tfhdAtom = tfhdAtom->siblingById(TrackFragmentHeader, false)) {
|
||||
tfhdAtom->parse();
|
||||
uint32 calculatedDataSize = 0;
|
||||
if(tfhdAtom->dataSize() < calculatedDataSize) {
|
||||
|
@ -1434,8 +1533,7 @@ void Mp4Track::internalParseHeader()
|
|||
m_istream->seekg(4, ios_base::cur);
|
||||
}
|
||||
}
|
||||
Mp4Atom *trunAtom = trafAtom->childById(TrackFragmentRun);
|
||||
while(trunAtom) {
|
||||
for(Mp4Atom *trunAtom = trafAtom->childById(TrackFragmentRun); trunAtom; trunAtom = trunAtom->siblingById(TrackFragmentRun, false)) {
|
||||
uint32 calculatedDataSize = 8;
|
||||
if(trunAtom->dataSize() < calculatedDataSize) {
|
||||
addNotification(NotificationType::Critical, "trun atom is truncated.", context);
|
||||
|
@ -1495,18 +1593,14 @@ void Mp4Track::internalParseHeader()
|
|||
}
|
||||
}
|
||||
}
|
||||
trunAtom = trunAtom->siblingById(TrackFragmentRun, false);
|
||||
}
|
||||
if(m_sampleSizes.empty() && defaultSampleSize) {
|
||||
m_sampleSizes.push_back(defaultSampleSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
tfhdAtom = tfhdAtom->siblingById(TrackFragmentHeader, false);
|
||||
}
|
||||
trafAtom = trafAtom->siblingById(TrackFragment, false);
|
||||
}
|
||||
moofAtom = moofAtom->siblingById(MovieFragment, false);
|
||||
}
|
||||
// set duration from "trun-information" if the duration has not been determined yet
|
||||
if(m_duration.isNull() && totalDuration) {
|
||||
|
@ -1515,7 +1609,7 @@ void Mp4Track::internalParseHeader()
|
|||
timeScale = trakAtom().container().timeScale();
|
||||
}
|
||||
if(timeScale) {
|
||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(totalDuration) / static_cast<double>(m_timeScale));
|
||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(totalDuration) / static_cast<double>(timeScale));
|
||||
}
|
||||
}
|
||||
// caluculate average bitrate
|
||||
|
|
|
@ -40,6 +40,15 @@ public:
|
|||
byte epConfig;
|
||||
};
|
||||
|
||||
class LIB_EXPORT Mpeg4VideoSpecificConfig
|
||||
{
|
||||
public:
|
||||
Mpeg4VideoSpecificConfig();
|
||||
|
||||
byte profile;
|
||||
std::string userData;
|
||||
};
|
||||
|
||||
class LIB_EXPORT Mpeg4ElementaryStreamInfo
|
||||
{
|
||||
public:
|
||||
|
@ -63,6 +72,7 @@ public:
|
|||
uint32 maxBitrate;
|
||||
uint32 averageBitrate;
|
||||
std::unique_ptr<Mpeg4AudioSpecificConfig> audioSpecificConfig;
|
||||
std::unique_ptr<Mpeg4VideoSpecificConfig> videoSpecificConfig;
|
||||
};
|
||||
|
||||
inline Mpeg4ElementaryStreamInfo::Mpeg4ElementaryStreamInfo() :
|
||||
|
@ -126,6 +136,7 @@ public:
|
|||
AvcConfiguration parseAvcConfiguration(Mp4Atom *avcConfigAtom);
|
||||
std::unique_ptr<Mpeg4ElementaryStreamInfo> parseMpeg4ElementaryStreamInfo(Mp4Atom *esDescAtom);
|
||||
std::unique_ptr<Mpeg4AudioSpecificConfig> parseAudioSpecificConfig(Mpeg4Descriptor *decSpecInfoDesc);
|
||||
std::unique_ptr<Mpeg4VideoSpecificConfig> parseVideoSpecificConfig(Mpeg4Descriptor *decSpecInfoDesc);
|
||||
|
||||
// methods to read the "index" (chunk offsets and sizes)
|
||||
std::vector<uint64> readChunkOffsets();
|
||||
|
|
Loading…
Reference in New Issue