diff --git a/abstracttrack.h b/abstracttrack.h index d636414..756ee88 100644 --- a/abstracttrack.h +++ b/abstracttrack.h @@ -19,6 +19,8 @@ namespace Media { enum class MediaType; enum class GeneralMediaFormat; +class MpegAudioFrameStream; +class WaveAudioStream; /*! * \brief Specifies the track type. @@ -33,11 +35,10 @@ enum class TrackType OggStream /**< The track is a Media::OggStream. */ }; -class MpegAudioFrameStream; - class LIB_EXPORT AbstractTrack : public StatusProvider { - friend class MpegAudioFrameStream; // this is a temporary solution, until I have a better design + friend class MpegAudioFrameStream; + friend class WaveAudioStream; public: virtual ~AbstractTrack(); diff --git a/avi/mediafourcc.cpp b/avi/mediafourcc.cpp deleted file mode 100644 index 66534e5..0000000 --- a/avi/mediafourcc.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "mediafourcc.h" - -#include "../mediaformat.h" - -namespace Media { - -namespace Fourccs { - -/*! - * \brief Returns the media format for the specified \a fourcc. - */ -MediaFormat fourccToMediaFormat(uint32 fourcc) { - switch(fourcc) { - case XvidMpeg4: - return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Asp); - default: return MediaFormat(); // TODO: cover more FOURCCs - } -} - -} - -} diff --git a/avi/mediafourcc.h b/avi/mediafourcc.h deleted file mode 100644 index be3ae7b..0000000 --- a/avi/mediafourcc.h +++ /dev/null @@ -1,354 +0,0 @@ -#ifndef MEDIAFOURCC_H -#define MEDIAFOURCC_H - -#include -#include - -namespace Media { - -class MediaFormat; - -namespace Fourccs { - -enum KnownValues { - AMParedesPredictor = 0x31393738, - VuyBlackmagic = 0x32565559, - Ivx1 = 0x33495630, - Ivx2 = 0x33495631, - Ivx3 = 0x33495632, - FfmpegDivxMsMpeg4V3 = 0x33495644, - Ivx4 = 0x33495658, - PlanarRgbCodec = 0x38425053, - AutodeskAnimatorCodecRle1 = 0x41415334, - AutodeskAnimatorCodecRle2 = 0x41415343, - KensingtonCodec = 0x41425952, - StreamboxActl2 = 0x4143544C, - Wavecodec = 0x41445631, - Advj = 0x4144564A, - IntelIndeoVideo32 = 0x4145494B, - ArrayVideooneMpeg1ICapture = 0x41454D49, - AutodeskAnimatorFlc256Color = 0x41464C43, - AfliAutodeskAnimatorFli256Color = 0x41464C49, - Cineform10BitVisuallyPerfectHdWavelet = 0x41484456, - Ajpg = 0x414A5047, - Ampg = 0x414D5047, - Anim = 0x414E494D, - AngelpotionDefinitive1 = 0x41503431, - AngelpotionDefinitive2 = 0x41503432, - AlparysoftLosslessCodec = 0x41534C43, - AsusVideo = 0x41535631, - AsusVideo2 = 0x41535632, - AsusVideo20 = 0x41535658, - Atm4 = 0x41544D34, - Aura2CodecYuv422 = 0x41555232, - Aura1CodecYuv411 = 0x41555241, - Avc1 = 0x41564331, - Avrn = 0x4156524E, - Ba81 = 0x42413831, - BinkVideo = 0x42494E4B, - Blz0 = 0x424C5A30, - ProsumerVideo = 0x42543230, - Btcv = 0x42544356, - BroadwayMpegCapturecompression = 0x42573130, - Byr1 = 0x42595231, - Byr2 = 0x42595232, - Cc12 = 0x43433132, - Cdvc = 0x43445643, - Cfcc = 0x43464343, - Cgdi = 0x43474449, - Cham = 0x4348414D, - WebcamJpeg = 0x434A5047, - Cmyk = 0x434D594B, - Cpla = 0x43504C41, - Cram = 0x4352414D, - CamstudioCodec = 0x43534344, - Ctrx = 0x43545258, - Cinepak = 0x43564944, - Cwlt = 0x43574C54, - ConexantYuv411 = 0x43585931, - ConexantYuv422 = 0x43585932, - CreativeYuv = 0x43595556, - Cyuy = 0x43595559, - D261 = 0x44323631, - D263 = 0x44323633, - Davc = 0x44415643, - Dcl1 = 0x44434C31, - Dcl2 = 0x44434C32, - Dcl3 = 0x44434C33, - Dcl4 = 0x44434C34, - Dcl5 = 0x44434C35, - DivxMpeg41 = 0x44495633, - DivxMpeg42 = 0x44495634, - Div5 = 0x44495635, - Divx = 0x44495658, - Dm4V = 0x444D3456, - RainbowRunnerHardwareCompression = 0x444D4231, - Dmb2 = 0x444D4232, - Dmk2 = 0x444D4B32, - Dsvd = 0x44535644, - TruemotionS = 0x4455434B, - Dvcpro = 0x44563235, - Dvcpro50 = 0x44563530, - Dvan = 0x4456414E, - Dvcs = 0x44564353, - Dve2 = 0x44564532, - Smpte370M = 0x44564831, - ConsumerDv50Mbps = 0x44564844, - ConsumerDv25Mbps = 0x44565344, - ConsumerDv125Mbps = 0x4456534C, - Dvx1 = 0x44565831, - Dvx2 = 0x44565832, - Dvx3 = 0x44565833, - DivxMpeg43 = 0x44583530, - Dxgm = 0x4458474D, - Dxtc = 0x44585443, - Dxtn = 0x4458544E, - ElsaQuickCodec = 0x454B5130, - Elk0 = 0x454C4B30, - EtymonixMpeg2Video = 0x454D3256, - Eyestream7Codec = 0x45533037, - Escp = 0x45534350, - EtreppidVideoCodec1 = 0x45545631, - EtreppidVideoCodec2 = 0x45545632, - Etvc = 0x45545643, - FfmpegCodec = 0x46465631, - Fljp = 0x464C4A50, - Ffmpeg = 0x464D5034, - FmscreenCaptureCodec = 0x464D5643, - FrapsCodec = 0x46505331, - ForwardMotionJpegWithAlphaChannel = 0x46525741, - ForwardMotionJpeg = 0x46525744, - Fvf1 = 0x46564631, - Geompeg4 = 0x47454F58, - Gjpg = 0x474A5047, - MotionLzw = 0x474C5A57, - MotionJpeg1 = 0x47504547, - Gwlt = 0x47574C54, - H260ThroughH269 = 0x48323630, - RawYuv422 = 0x48445943, - H265Hevc = 0x48455643, - HuffmanLosslessCodec = 0x48465955, - Hmcr = 0x484D4352, - Hmrr = 0x484D5252, - ItuH263 = 0x49323633, - Iclb = 0x49434C42, - Igor = 0x49474F52, - Ijpg = 0x494A5047, - Ilvc = 0x494C5643, - Ilvr = 0x494C5652, - GigaAviDvCodec = 0x49504456, - Indeo21 = 0x49523231, - Iraw = 0x49524157, - Isme = 0x49534D45, - Indeo3 = 0x49563330, - Indeo32 = 0x49563332, - IndeoInteractive1 = 0x49563430, - IndeoInteractive2 = 0x49563530, - Jbyr = 0x4A425952, - JpegStillImage = 0x4A504547, - JpegLight = 0x4A50474C, - Kmvc = 0x4B4D5643, - L261 = 0x4C323631, - LeadH263 = 0x4C323633, - Lbyr = 0x4C425952, - LeadmcmwVideoCodec = 0x4C434D57, - LeadMjpeg20001 = 0x4C435732, - LeadVideoCodec = 0x4C454144, - Lgry = 0x4C475259, - LeadJpeg411 = 0x4C4A3131, - LeadJpeg422 = 0x4C4A3232, - LeadMjpeg20002 = 0x4C4A324B, - LeadJpeg444 = 0x4C4A3434, - LeadMjpegCodec = 0x4C4A5047, - LeadMpeg2VideoCodec = 0x4C4D5032, - LeadMpeg4VideoCodec = 0x4C4D5034, - Lsvc = 0x4C535643, - Lsvm = 0x4C53564D, - LightningStrikeVideoCodec = 0x4C535658, - LempelzivoberhumerCodec = 0x4C5A4F31, - M261 = 0x4D323631, - M263 = 0x4D323633, - M4CcM4Cc = 0x4D344343, - M4S2 = 0x4D345332, - Mc12 = 0x4D433132, - Mcam = 0x4D43414D, - MotionJpeg2000 = 0x4D4A3243, - MotionJpeg2 = 0x4D4A5047, - Mmes = 0x4D4D4553, - EvalDownload1 = 0x4D503241, - EvalDownload2 = 0x4D503254, - EvalDownload3 = 0x4D503256, - Mpeg4 = 0x4D503432, - Mp43 = 0x4D503433, - EvalDownload4 = 0x4D503441, - Mp4S = 0x4D503453, - EvalDownload5 = 0x4D503454, - EvalDownload6 = 0x4D503456, - Mpeg = 0x4D504547, - Mpg4 = 0x4D504734, - Mpgi = 0x4D504749, - Mr16 = 0x4D523136, - Mrca = 0x4D524341, - Mrle = 0x4D524C45, - Msvc = 0x4D535643, - Avimszh = 0x4D535A48, - Mtx1ThroughMtx9 = 0x4D545831, - MotionPixelsMvi1Codec = 0x4D564931, - MotionPixelsMvi2Codec = 0x4D564932, - AwareMotionWavelets = 0x4D575631, - Navi = 0x4E415649, - Ndsc = 0x4E445343, - Ndsm = 0x4E44534D, - Ndsp = 0x4E445350, - Ndss = 0x4E445353, - Ndxc = 0x4E445843, - Ndxh = 0x4E445848, - Ndxp = 0x4E445850, - Ndxs = 0x4E445853, - Nhvu = 0x4E485655, - Ntn1 = 0x4E544E31, - Ntn2 = 0x4E544E32, - Nvds = 0x4E564453, - Nvhs = 0x4E564853, - Nvs0Nvs5 = 0x4E565330, - Nvt0Nvt5 = 0x4E565430, - DvcCodec = 0x50445643, - Pgvv = 0x50475656, - Phmo = 0x50484D4F, - Pim1 = 0x50494D31, - Pim2 = 0x50494D32, - PegasusLosslessJpeg = 0x50494D4A, - VideoXl = 0x5049584C, - Pjpg = 0x504A5047, - Pvez = 0x5056455A, - Pvmm = 0x50564D4D, - PegasusWavelet2000Compression = 0x50565732, - Qpeg = 0x51504547, - Qpeq = 0x51504551, - Rgbt = 0x52474254, - Rle = 0x524C450, - Rle4 = 0x524C4534, - Rle8 = 0x524C4538, - Rmp4 = 0x524D5034, - AppleVideo = 0x52505A41, - Rt21 = 0x52543231, - Rv20 = 0x52563230, - Rv30 = 0x52563330, - Rv40 = 0x52563430, - VideocapC210 = 0x53343232, - San3 = 0x53414E33, - Sdcc = 0x53444343, - Sedg = 0x53454447, - SurfaceFittingMethod = 0x53464D43, - Smp4 = 0x534D5034, - Smsc = 0x534D5343, - Smsd = 0x534D5344, - Smsv = 0x534D5356, - Sp40 = 0x53503430, - Sp44 = 0x53503434, - Sp54 = 0x53503534, - Spig = 0x53504947, - Sqz2 = 0x53515A32, - Stva = 0x53545641, - Stvb = 0x53545642, - Stvc = 0x53545643, - Stvx = 0x53545658, - Stvy = 0x53545659, - VideoR1 = 0x53563130, - SorensonVideo1 = 0x53565131, - Svq3 = 0x53565133, - Tlms = 0x544C4D53, - Tlst = 0x544C5354, - Tm20 = 0x544D3230, - Tm2X = 0x544D3258, - Tmic = 0x544D4943, - Tmot = 0x544D4F54, - TruemotionRt20 = 0x54523230, - TechsmithScreenCaptureCodec = 0x54534343, - Tv10 = 0x54563130, - Tvjp = 0x54564A50, - Tvmj = 0x54564D4A, - Ty0N = 0x5459304E, - Ty2C = 0x54593243, - Ty2N = 0x5459324E, - Clearvideo = 0x55434F44, - Ultimotion = 0x554C5449, - V210 = 0x56323130, - V261 = 0x56323631, - V655 = 0x56363535, - Vcr1 = 0x56435231, - Vcr2 = 0x56435232, - Vcr39 = 0x56435233, - Vdct = 0x56444354, - Vdom = 0x56444F4D, - Vdow = 0x56444F57, - VideotizerYuvCodec = 0x5644545A, - Videogrampix = 0x56475058, - Vids = 0x56494453, - VfapiCodec = 0x56494650, - Vivo = 0x5649564F, - Vixl = 0x5649584C, - Vlv1 = 0x564C5631, - Vp30 = 0x56503330, - Vp31 = 0x56503331, - Vp40 = 0x56503430, - Vp50 = 0x56503530, - Vp60 = 0x56503630, - Vp61 = 0x56503631, - Vp62 = 0x56503632, - Vp70 = 0x56503730, - Vp80 = 0x56503830, - Vqc1 = 0x56514331, - Vqc2 = 0x56514332, - Vqjc = 0x56514A43, - VssVideo = 0x56535356, - Vuuu = 0x56555555, - Vx1K = 0x5658314B, - Vx2K = 0x5658324B, - Vxsp = 0x56585350, - AtiYuv1 = 0x56595539, - AtiYuv2 = 0x56595559, - Wbvc = 0x57425643, - Wham = 0x5748414D, - WinnovSoftwareCompression = 0x57494E58, - WinbondJpeg = 0x574A5047, - Wmv1 = 0x574D5631, - Wmv2 = 0x574D5632, - WindowsMediaVideo9 = 0x574D5633, - Wmva = 0x574D5641, - WinnovHardwareCompression = 0x574E5631, - Wvc1 = 0x57564331, - X263 = 0x58323633, - H264 = 0x58323634, - Xlv0 = 0x584C5630, - Xmpg = 0x584D5047, - XvidMpeg4 = 0x58564944, - Xwv0Xwv9 = 0x58575630, - Xxan = 0x5858414E, - BppGrayscaleVideo = 0x5931360, - Y411 = 0x59343131, - BrooktreeYuv411 = 0x59343150, - Y444 = 0x59343434, - Y8 = 0x593800, - Yc12 = 0x59433132, - Yuv8 = 0x59555638, - Yuv9RawFormat = 0x59555639, - Yuvp = 0x59555650, - Yuy2 = 0x59555932, - Yuyv = 0x59555956, - Yuv420Planar = 0x59563132, - Yv16 = 0x59563136, - Yv92 = 0x59563932, - Zlib = 0x5A4C4942, - TheDoxboxProject = 0x5A4D4256, - Zpeg = 0x5A504547, - Zygovideo = 0x5A59474F -}; - -LIB_EXPORT MediaFormat fourccToMediaFormat(uint32 fourcc); - -} - -} - -#endif // MEDIAFOURCC_H diff --git a/general.pri b/general.pri index 9156999..9f790b4 100644 --- a/general.pri +++ b/general.pri @@ -12,7 +12,17 @@ unix { QMAKE_LFLAGS += "-Wl,--rpath=./" } # prefix -targetprefix = . +targetprefix = $$(TARGET_PREFIX) +equals(targetprefix, "") { + win32 { + targetprefix = ../../.. + } else { + targetprefix = ../.. + } +} +message("Using target prefix \"$${targetprefix}\".") +# print install root +message("Using install root \"$$(INSTALL_ROOT)\".") # target CONFIG(debug, debug|release) { TARGET = $$targetprefix/$${projectname}d diff --git a/genericfileelement.h b/genericfileelement.h index 9007fd2..1d85e51 100644 --- a/genericfileelement.h +++ b/genericfileelement.h @@ -562,13 +562,11 @@ template typename GenericFileElement::implementationType *GenericFileElement::childById(const GenericFileElement::identifierType &id) { parse(); // ensure element is parsed - implementationType *child = firstChild(); - while(child) { + for(implementationType *child = firstChild(); child; child = child->nextSibling()) { child->parse(); if(child->id() == id) { return child; } - child = child->nextSibling(); } return nullptr; } @@ -591,13 +589,11 @@ template typename GenericFileElement::implementationType *GenericFileElement::siblingById(const GenericFileElement::identifierType &id, bool includeThis) { parse(); // ensure element is parsed - implementationType *sibling = includeThis ? static_cast(this) : nextSibling(); - while(sibling) { + for(implementationType *sibling = includeThis ? static_cast(this) : nextSibling(); sibling; sibling = sibling->nextSibling()) { sibling->parse(); if(sibling->id() == id) { return sibling; } - sibling = sibling->nextSibling(); } return nullptr; } diff --git a/matroska/matroskatrack.cpp b/matroska/matroskatrack.cpp index 7de4489..a020a87 100644 --- a/matroska/matroskatrack.cpp +++ b/matroska/matroskatrack.cpp @@ -4,7 +4,8 @@ #include "matroskaid.h" #include "../avi/bitmapinfoheader.h" -#include "../avi/mediafourcc.h" +#include "../wav/waveaudiostream.h" +#include "../mp4/mp4ids.h" #include "../mediaformat.h" #include "../exceptions.h" @@ -81,6 +82,8 @@ MediaFormat MatroskaTrack::codecIdToMediaFormat(const string &codecId) fmt.general = GeneralMediaFormat::Theora; } else if(part1 == "V_PRORES") { fmt.general = GeneralMediaFormat::ProRes; + } else if(part1 == "V_VP8") { + fmt.general = GeneralMediaFormat::Vp8; } else if(part1 == "A_MPEG") { fmt.general = GeneralMediaFormat::Mpeg1Audio; if(part2 == "L1") { @@ -345,7 +348,6 @@ void MatroskaTrack::internalParseHeader() switch(m_format.general) { EbmlElement *codecPrivateElement; case GeneralMediaFormat::MicrosoftVideoCodecManager: - case GeneralMediaFormat::MicrosoftAudioCodecManager: if((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate))) { // parse bitmap info header to determine actual format if(codecPrivateElement->dataSize() >= 0x28) { @@ -356,7 +358,20 @@ void MatroskaTrack::internalParseHeader() m_formatId += " \""; m_formatId += interpretIntegerAsString(bitmapInfoHeader.compression); m_formatId += "\""; - m_format += Fourccs::fourccToMediaFormat(bitmapInfoHeader.compression); + m_format += FourccIds::fourccToMediaFormat(bitmapInfoHeader.compression); + } else { + addNotification(NotificationType::Critical, "BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context); + } + } + break; + case GeneralMediaFormat::MicrosoftAudioCodecManager: + if((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate))) { + // parse WAVE header to determine actual format + if(codecPrivateElement->dataSize() >= 16) { + m_istream->seekg(codecPrivateElement->dataOffset()); + WaveFormatHeader waveFormatHeader; + waveFormatHeader.parse(reader()); + WaveAudioStream::addInfo(waveFormatHeader, *this); } else { addNotification(NotificationType::Critical, "BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context); } diff --git a/mediaformat.cpp b/mediaformat.cpp index 8db6d36..be1aadb 100644 --- a/mediaformat.cpp +++ b/mediaformat.cpp @@ -137,12 +137,14 @@ const char *MediaFormat::name() const } case GeneralMediaFormat::Theora: return "Theora"; case GeneralMediaFormat::Tiff: return "Tagged Image File Format"; + case GeneralMediaFormat::TimedText: return "Timed Text"; 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::Vp8: return "VP8"; case GeneralMediaFormat::WavPack: return "WavPack"; default: return "unknown"; } @@ -280,12 +282,14 @@ const char *MediaFormat::abbreviation() const } case GeneralMediaFormat::Theora: return "Theora"; case GeneralMediaFormat::Tiff: return "TIFF"; + case GeneralMediaFormat::TimedText: return "Timed Text"; 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::Vp8: return "VP8"; case GeneralMediaFormat::WavPack: return "WavPack"; default: return ""; } diff --git a/mediaformat.h b/mediaformat.h index 0362278..2f989c5 100644 --- a/mediaformat.h +++ b/mediaformat.h @@ -71,12 +71,14 @@ enum class GeneralMediaFormat TextSubtitle, /**< Text subtitle */ Theora, /**< Theora */ Tiff, /**< TIFF */ + TimedText, /** < Timed Text */ Tta, /**< The True Audio lessles audio compressor */ UncompressedVideoFrames, /**< uncompressed RGB */ Vc1, /**< VC-1 */ VobBtn, /**< VobBtn */ VobSub, /**< VobSub */ Vorbis, /**< Vorbis */ + Vp8, /** < VP8 */ WavPack /**< WavPack */ }; diff --git a/mp4/mp4atom.cpp b/mp4/mp4atom.cpp index 807f790..de92b61 100644 --- a/mp4/mp4atom.cpp +++ b/mp4/mp4atom.cpp @@ -193,7 +193,7 @@ bool Mp4Atom::isPadding() const uint64 Mp4Atom::firstChildOffset() const { using namespace Mp4AtomIds; - using namespace Mp4FormatIds; + using namespace FourccIds; if(isParent()) { switch(id()) { case Meta: return headerSize() + 0x4; diff --git a/mp4/mp4ids.cpp b/mp4/mp4ids.cpp index ffbce7e..b683c2e 100644 --- a/mp4/mp4ids.cpp +++ b/mp4/mp4ids.cpp @@ -40,42 +40,64 @@ namespace Mp4MediaTypeIds { * \brief Encapsulates all supported MP4 media format IDs (aka "FOURCCs"). * \sa http://wiki.multimedia.cx/?title=QuickTime_container */ -namespace Mp4FormatIds { +namespace FourccIds { MediaFormat fourccToMediaFormat(uint32 fourccId) { switch(fourccId) { - case Mp4FormatIds::Mpeg4Video: + case Mpeg: + return GeneralMediaFormat::Mpeg1Video; + case Mpeg2Imx30: case Mpeg2Imx50: + return GeneralMediaFormat::Mpeg2Video; + case Mpeg4Video: return GeneralMediaFormat::Mpeg4Video; - case Mp4FormatIds::Avc1: - case Mp4FormatIds::Avc2: - case Mp4FormatIds::Avc3: - case Mp4FormatIds::Avc4: + 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 Mp4FormatIds::H263: + case H263: case XvidDecoder1: case XvidDecoder2: + case XvidDecoder3: case XvidDecoder4: case XvidDecoder5: + case Divx5Decoder: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Asp); - case Mp4FormatIds::Tiff: + case Divx4Decoder1: case Divx4Decoder2: case Divx4Decoder3: + case Divx4Decoder4: case Divx4Decoder5: case Divx4Decoder6: case Divx4Decoder7: + return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4Sp); + case Tiff: return GeneralMediaFormat::Tiff; - case Mp4FormatIds::Raw: + case AppleTextAtsuiCodec: + return GeneralMediaFormat::TimedText; + case Raw: return GeneralMediaFormat::UncompressedVideoFrames; - case Mp4FormatIds::Jpeg: + case Jpeg: return GeneralMediaFormat::Jpeg; - case Mp4FormatIds::Gif: + case Gif: return GeneralMediaFormat::Gif; - case Mp4FormatIds::AdpcmAcm: + case Png: + return GeneralMediaFormat::Png; + case AdpcmAcm: return GeneralMediaFormat::AdpcmAcm; - case Mp4FormatIds::ImaadpcmAcm: + case ImaadpcmAcm: return GeneralMediaFormat::ImaadpcmAcm; - case Mp4FormatIds::Mp3CbrOnly: + case Mp3CbrOnly: case Mp3: return MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer3); - case Mp4FormatIds::Mpeg4Audio: + case Mpeg4Audio: return GeneralMediaFormat::Aac; - case Mp4FormatIds::Alac: + case Alac: return GeneralMediaFormat::Alac; - case Mp4FormatIds::Ac3: + case Ac3: return GeneralMediaFormat::Ac3; - case Mp4FormatIds::Ac4: + case Ac4: return GeneralMediaFormat::Ac4; + case Rv20: case Rv30: case Rv40: + return GeneralMediaFormat::RealVideo; + case Int24: case Int32: + return MediaFormat(GeneralMediaFormat::Pcm); + case Int16Be: + return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntBe); + case Int16Le: + return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe); + case FloatingPoint32Bit: case FloatingPoint64Bit: + return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee); + // TODO: map more FOURCCs default: return GeneralMediaFormat::Unknown; } @@ -113,7 +135,7 @@ MediaFormat streamObjectTypeFormat(byte streamObjectTypeId) case ParameterSetsForAvc: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg4AvcParams); case Als: return GeneralMediaFormat::Als; case Sa0c: return GeneralMediaFormat::Sa0c; - case Aac: return GeneralMediaFormat::Aac; + case Aac: return MediaFormat(GeneralMediaFormat::Aac, SubFormats::AacMpeg4LowComplexityProfile); case Mpeg2VideoSimpleProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2SimpleProfile); case Mpeg2VideoMainProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2SnrProfile); case Mpeg2VideoSnrProfile: return MediaFormat(GeneralMediaFormat::Mpeg4Video, SubFormats::Mpeg2SpatialProfile); diff --git a/mp4/mp4ids.h b/mp4/mp4ids.h index ce8d7cd..7924b47 100644 --- a/mp4/mp4ids.h +++ b/mp4/mp4ids.h @@ -135,36 +135,259 @@ enum KnownValue : uint32 { }; } -namespace Mp4FormatIds { +namespace FourccIds { enum KnownValue : uint32 { - Cinepak = 0x63766964, /**< Cinepak */ - Mpeg4Video = 0x6d703476, /**< MPEG-4 video */ - Graphics = 0x736D6320, /**< Graphics */ + Ac3 = 0x61632d33, /**< Dolby Digital */ + Ac4 = 0x61632d34, /**< ? */ + AdpcmAcm = 0x6D730002, /**< ? */ + Agsm = 0x6167736D, + Alac = 0x616C6163, /**< Apple Losless Audio Codec */ + Alaw = 0x616C6177, + Alaw21 = 0x616C6177, + AlphaCompositor = 0x626C6E64, + AlphaGain = 0x6761696E, + AmrNarrowband = 0x73616D72, Animation = 0x726C6520, /**< Animation */ + Appl1 = 0x6476690, + Appl2 = 0x6C70630, + Apple16BitGray = 0x62313667, + Apple32BitGrayWithAlpha = 0x62333261, + Apple48BitRgb = 0x62343872, + Apple64BitArgb1 = 0x62363461, + Apple64BitArgb2 = 0x62617365, + Apple64BitArgb3 = 0x626C6974, + AppleAnimation = 0x726C6520, + AppleAvrJpeg = 0x61767220, + AppleBmp = 0x57524C45, + AppleCinepak = 0x63766964, + AppleCmyk = 0x636D796B, + AppleComponentVideoYuv422 = 0x79757632, + AppleCurve = 0x70617468, + AppleDvc = 0x64766320, + AppleDvcpro = 0x64767070, + AppleDvcpro501 = 0x6476356E, + AppleDvcpro502 = 0x64763570, + AppleDvcpro50Ntsc = 0x6476356E, + AppleDvcpro50Pal = 0x64763570, + AppleDvcproPal = 0x64767070, + AppleDvDvcproNtsc = 0x6476630, + AppleDvp = 0x64766370, + AppleDvPal = 0x64766370, + AppleFlc = 0x666C6963, + AppleGif = 0x67696620, + AppleGraphics = 0x736D630, + AppleGsm101 = 0x6167736D, + AppleH261 = 0x68323631, + AppleIntermediateCodec = 0x69636F64, + AppleLossless = 0x616C6163, + AppleMacpaint = 0x504E5447, + AppleMicrosoftVideo1 = 0x6D737663, + AppleMotionJpegA = 0x6D6A7061, + AppleMotionJpegB = 0x6D6A7062, + AppleMpeg4Compressor = 0x6D703476, + AppleMpeg4Decompressor = 0x6D703476, + AppleOpendmlJpeg = 0x646D6231, + ApplePhotoCd = 0x6B706364, + ApplePhotoJpeg = 0x6A706567, + ApplePixletVideo = 0x70786C74, + ApplePlanarRgb = 0x38425053, + ApplePng = 0x706E670, + AppleQuickdraw = 0x71647277, + AppleR408 = 0x72343038, + AppleScalingCodec = 0x7363616C, + AppleSgi = 0x2E534749, + AppleSorensonYuv9Codec = 0x73797639, + AppleTextAtsuiCodec = 0x74657874, + AppleTga = 0x7467610, + AppleTiff = 0x74696666, + AppleV408 = 0x76343038, + AppleVcH263 = 0x68323633, AppleVideo = 0x72707A61, /**< Apple video */ - Png = 0x706E6720, /**< Portable Network Graphics */ + AppleYuv420Codec1 = 0x6A343230, + AppleYuv420Codec2 = 0x6D797576, + AppleYuv420Codec3 = 0x79343230, + AppleYuv422Codec2Vuy = 0x32767579, + AppleYuv422Codec4 = 0x79757678, + AppleYuv422CodecYuvs = 0x79757673, + AppleYuv422CodecYuvu = 0x79757675, + Avc0Media = 0x64726D69, Avc1 = 0x61766331, /**< H.264/MPEG-4 AVC video */ Avc2 = 0x61766332, /**< H.264/MPEG-4 AVC video */ Avc3 = 0x61766333, /**< H.264/MPEG-4 AVC video */ Avc4 = 0x61766334, /**< H.264/MPEG-4 AVC video */ - H263 = 0x68323633, /**< H.263/MPEG-4 ASP video */ - Tiff = 0x74696666, /**< Tagged Image File Format */ - Jpeg = 0x6a706567, /**< JPEG */ - Raw = 0x72617720, /**< Uncompressed RGB */ + Blur = 0x626C7572, + Bps8 = 0x38627073, + BrightnessAndContrast = 0x6272636F, + ChannelCompositor = 0x6368616E, + ChromaKey = 0x636B6579, + Cinepak = 0x63766964, /**< Cinepak */ + Cloud = 0x636C6F75, + ColorStyle = 0x736F6C72, + Colorsync = 0x73796E63, + ColorTint = 0x74696E74, + CrossFade = 0x64736C76, + Cvid = 0x63766964, + Divx3Decoder1 = 0x41503431, + Divx3Decoder10 = 0x636F6C30, + Divx3Decoder11 = 0x636F6C31, + Divx3Decoder12 = 0x64697633, + Divx3Decoder13 = 0x64697634, + Divx3Decoder14 = 0x64697635, + Divx3Decoder15 = 0x64697636, + Divx3Decoder16 = 0x6D703433, + Divx3Decoder17 = 0x6D706733, + Divx3Decoder2 = 0x434F4C30, + Divx3Decoder3 = 0x434F4C31, + Divx3Decoder4 = 0x44495633, + Divx3Decoder5 = 0x44495634, + Divx3Decoder6 = 0x44495635, + Divx3Decoder7 = 0x44495636, + Divx3Decoder8 = 0x4D503433, + Divx3Decoder9 = 0x4D504733, + Divx4Decoder1 = 0x44495658, + Divx4Decoder2 = 0x4D345332, + Divx4Decoder3 = 0x4D503453, + Divx4Decoder4 = 0x554D5034, + Divx4Decoder5 = 0x64697678, + Divx4Decoder6 = 0x6D347332, + Divx4Decoder7 = 0x6D703473, + Divx5Decoder = 0x44583530, + Drm = 0x64726D73, + Dvca = 0x64766361, + DvcPro501 = 0x64763570, + DvcPro502 = 0x6476356E, + DvcProPal = 0x64767070, + EdgeDetection = 0x65646765, + Emboss = 0x656D6273, + Explode = 0x78706C6F, + FilmNoise = 0x666D6E73, + Fire = 0x66697265, + FlashPixImage = 0x66706978, + FlashScreenVideoDecoder = 0x46535631, + FloatingPoint32Bit = 0x666C3332, + FloatingPoint64Bit = 0x666C3634, + GeneralConvolution = 0x67656E6B, Gif = 0x67696620, /**< CompuServe Graphics Interchange Format */ - NtscDv25Video = 0x64766320, /**< NTSC DV-25 video */ - PalDv25Video = 0x64766370, /**< PAL DV-25 video */ + Glass = 0x676C6173, + GradientWipe = 0x6D617474, + Graphics = 0x736D6320, /**< Graphics */ + H263 = 0x68323633, /**< H.263/MPEG-4 ASP video */ + H264Decoder1 = 0x44415643, + H264Decoder2 = 0x48323634, + H264Decoder3 = 0x56535348, + H264Decoder4 = 0x58323634, + H264Decoder5 = 0x68323634, + H264Decoder6 = 0x78323634, + Hdv3 = 0x68647633, + HslBalance = 0x68736C62, + Ima4 = 0x696D6134, + Ima41 = 0x696D6134, + ImaadpcmAcm = 0x6D730011, /**< ? */ + Implode = 0x6D706C6F, + Int16Be = 0x74776F73, + Int16Le = 0x736F7774, + Int24 = 0x696E3234, + Int32 = 0x696E3332, + Iris = 0x736D7032, + IvxDecoder1 = 0x33495632, + IvxDecoder2 = 0x33495644, + IvxDecoder3 = 0x33697632, + IvxDecoder4 = 0x33697664, + Jpeg = 0x6a706567, /**< JPEG */ + Jpeg2000Decoder = 0x6D6A7032, + Law21 = 0x756C6177, + LensFlare = 0x6C656E73, + Lle = 0x726C6520, + Mac3 = 0x6D616333, + Mac6 = 0x6D616336, + Mace31 = 0x4D414333, + Mace61 = 0x4D414336, + MatrixWipe = 0x736D7034, MotionJpegA = 0x6D6A7061, /**< Motion-JPEG (format A) */ MotionJpegB = 0x6D6A7062, /**< Motion-JPEG (format B) */ Mp3 = 0x2e6d7033, /**< MPEG-1 Layer 3 */ + Mp3CbrOnly = 0x6D730055, /**< MPEG-1 Layer 3 (constant bitrate only) */ + Mpeg = 0x4D504547, + Mpeg2Imx30 = 0x6D78336E, + Mpeg2Imx50 = 0x6D783570, Mpeg4Audio = 0x6d703461, /**< MPEG-4 audio */ + Mpeg4Decoder1 = 0x464D5034, + Mpeg4Decoder2 = 0x53454447, + Mpeg4Decoder3 = 0x57563146, 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) */ + Mpeg4Video = 0x6d703476, /**< MPEG-4 video */ + MsMpeg4V1Decoder1 = 0x44495631, + MsMpeg4V1Decoder2 = 0x4D504734, + MsMpeg4V1Decoder3 = 0x64697631, + MsMpeg4V1Decoder4 = 0x6D706734, + MsMpeg4V2Decoder5 = 0x44495632, + MsMpeg4V2Decoder6 = 0x4D503432, + MsMpeg4V2Decoder7 = 0x64697632, + MsMpeg4V2Decoder8 = 0x6D703432, + NtscDv25Video = 0x64766320, /**< NTSC DV-25 video */ + Oggs = 0x4F676753, + PalDv25Video = 0x64766370, /**< PAL DV-25 video */ + PdfImage = 0x70646620, + Png = 0x706E6720, /**< Portable Network Graphics */ + Push = 0x70757368, + Qclp = 0x51636C70, + QdesignMusic1Decoder = 0x51444D43, + QdesignMusic2 = 0x51444D32, + Qdmc = 0x51444D43, + Qdrw = 0x71647277, + QtvrCubicCodec = 0x63757061, + QtvrCylindricalCodec = 0x6C747061, + QualcommPurevoice = 0x51636C70, + QualcommQcelp = 0x51636C71, + Radial = 0x736D7033, + Raw = 0x72617720, /**< Uncompressed RGB */ + RgbBalance = 0x72676262, + Ripple = 0x7269706C, + Rpza = 0x72707A61, + Rv20 = 0x52563230, + Rv30 = 0x52563330, + Rv40 = 0x52563430, + Sharpen = 0x73687270, + Slide = 0x736C6964, + Smc = 0x736D6320, + SorensonH263Decoder = 0x464C5631, + SorensonVideo3Compressor = 0x53565133, + SorensonVideoDecompressor = 0x53565131, + Sowt = 0x736F7774, + SpecialEffectsAndFilters = 0x67656666, + Svq1 = 0x73767131, + Svq3 = 0x73767133, + Tiff = 0x74696666, /**< Tagged Image File Format */ + TravelingMatte = 0x74726176, + TruemotionVp6Decoder1 = 0x56503632, + TruemotionVp6Decoder2 = 0x56503646, + Twos = 0x74776F73, + Ulaw = 0x756C6177, + Ulaw21 = 0x756C6177, + VcmImageCodec = 0x4D6A7067, + Vdva = 0x76647661, + WindowsMediaAudio7 = 0x574D4131, + WindowsMediaAudio9Professional = 0x574D4133, + WindowsMediaAudio9Standard = 0x574D4132, + Wipe = 0x736D7074, + WmvImageCodec1 = 0x4D347332, + WmvImageCodec2 = 0x4D703432, + WmvImageCodec3 = 0x4D703433, + WmvImageCodec4 = 0x4D703453, + WmvImageCodec5 = 0x574D5631, + WmvImageCodec6 = 0x574D5632, + WmvImageCodec7 = 0x574D5633, + XvidDecoder1 = 0x424C5A30, + XvidDecoder2 = 0x58564944, + XvidDecoder3 = 0x58564958, + XvidDecoder4 = 0x58766944, + XvidDecoder5 = 0x78766964, + Yuv422HardwareAccelerationCodecYuvs1 = 0x32767579, + Yuv422HardwareAccelerationCodecYuvs2 = 0x61633136, + Yuv422HardwareAccelerationCodecYuvs3 = 0x61633332, + Yuv422HardwareAccelerationCodecYuvs4 = 0x61634247, + Yuv422HardwareAccelerationCodecYuvs5 = 0x79757673, + Zoom = 0x7A6F6F6D }; LIB_EXPORT MediaFormat fourccToMediaFormat(uint32 fourccId); diff --git a/mp4/mp4tagfield.cpp b/mp4/mp4tagfield.cpp index d4df8aa..015aa8d 100644 --- a/mp4/mp4tagfield.cpp +++ b/mp4/mp4tagfield.cpp @@ -79,30 +79,28 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) ilstChild.parse(); // ensure child has been parsed setId(ilstChild.id()); context = "parsing MP4 tag field " + ilstChild.idToString(); - Mp4Atom *dataAtom = ilstChild.firstChild(); iostream &stream = ilstChild.stream(); BinaryReader &reader = ilstChild.container().reader(); - int dataAtomFound = 0; - int meanAtomFound = 0; - int nameAtomFound = 0; - while(dataAtom) { + int dataAtomFound = 0, meanAtomFound = 0, nameAtomFound = 0; + for(Mp4Atom *dataAtom = ilstChild.firstChild(); dataAtom; dataAtom = dataAtom->nextSibling()) { try { dataAtom->parse(); - if((dataAtom->id() == Mp4AtomIds::Data) && (dataAtom->totalSize() > 16)) { - ++dataAtomFound; - if(dataAtomFound > 1) { - if(dataAtomFound == 2) { - addNotification(NotificationType::Warning, "Tag atom contains more than one data atom. The addiational data atoms will be ignored.", context); - } - dataAtom = dataAtom->nextSibling(); + if(dataAtom->id() == Mp4AtomIds::Data) { + if(dataAtom->dataSize() < 8) { + addNotification(NotificationType::Warning, "Truncated child atom \"data\" in tag atom (ilst child) found. (will be ignored)", context); continue; } - stream.seekg(dataAtom->startOffset() + 8); - if(reader.readByte() != 0) { - addNotification(NotificationType::Warning, "The version indicator byte is not zero, the tag atom might not be parsed correctly.", context); + if(++dataAtomFound > 1) { + if(dataAtomFound == 2) { + addNotification(NotificationType::Warning, "Multiple \"data\" child atom in tag atom (ilst child) found. (will be ignored)", context); + } + continue; } - m_parsedRawDataType = reader.readUInt24BE(); - setTypeInfo(m_parsedRawDataType); + stream.seekg(dataAtom->dataOffset()); + if(reader.readByte() != 0) { + addNotification(NotificationType::Warning, "The version indicator byte is not zero, the tag atom might be unsupported and hence not be parsed correctly.", context); + } + setTypeInfo(m_parsedRawDataType = reader.readUInt24BE()); try { // try to show warning if parsed raw data type differs from expected raw data type for this atom id vector expectedRawDataTypes = this->expectedRawDataTypes(); if(find(expectedRawDataTypes.cbegin(), expectedRawDataTypes.cend(), m_parsedRawDataType) == expectedRawDataTypes.cend()) { @@ -115,8 +113,8 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) m_langIndicator = reader.readUInt16BE(); switch(m_parsedRawDataType) { case RawDataType::Utf8: case RawDataType::Utf16: - stream.seekg(dataAtom->startOffset() + 16); - value().assignText(reader.readString(dataAtom->totalSize() - 16), (m_parsedRawDataType == RawDataType::Utf16) ? TagTextEncoding::Utf16BigEndian : TagTextEncoding::Utf8); + stream.seekg(dataAtom->dataOffset() + 8); + value().assignText(reader.readString(dataAtom->dataSize() - 8), (m_parsedRawDataType == RawDataType::Utf16) ? TagTextEncoding::Utf16BigEndian : TagTextEncoding::Utf8); break; case RawDataType::Gif: case RawDataType::Jpeg: case RawDataType::Png: case RawDataType::Bmp: { switch(m_parsedRawDataType) { @@ -135,21 +133,21 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) default: ; } - streamsize coverSize = dataAtom->totalSize() - 16; + streamsize coverSize = dataAtom->dataSize() - 8; unique_ptr coverData = make_unique(coverSize); stream.read(coverData.get(), coverSize); value().assignData(move(coverData), coverSize, TagDataType::Picture); break; } case RawDataType::BeSignedInt: { int number = 0; - if(dataAtom->totalSize() > (16 + 4)) { + if(dataAtom->dataSize() > (8 + 4)) { addNotification(NotificationType::Warning, "Data atom stores integer of invalid size. Trying to read data anyways.", context); } - if(dataAtom->totalSize() >= (16 + 4)) { + if(dataAtom->dataSize() >= (8 + 4)) { number = reader.readInt32BE(); - } else if(dataAtom->totalSize() == (16 + 2)) { + } else if(dataAtom->dataSize() == (8 + 2)) { number = reader.readInt16BE(); - } else if(dataAtom->totalSize() == (16 + 1)) { + } else if(dataAtom->dataSize() == (8 + 1)) { number = reader.readChar(); } switch(ilstChild.id()) { @@ -162,14 +160,14 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) break; } case RawDataType::BeUnsignedInt: { int number = 0; - if(dataAtom->totalSize() > (16 + 4)) { + if(dataAtom->dataSize() > (8 + 4)) { addNotification(NotificationType::Warning, "Data atom stores integer of invalid size. Trying to read data anyways.", context); } - if(dataAtom->totalSize() >= (16 + 4)) { + if(dataAtom->dataSize() >= (8 + 4)) { number = static_cast(reader.readUInt32BE()); - } else if(dataAtom->totalSize() == (16 + 2)) { + } else if(dataAtom->dataSize() == (8 + 2)) { number = static_cast(reader.readUInt16BE()); - } else if(dataAtom->totalSize() == (16 + 1)) { + } else if(dataAtom->dataSize() == (8 + 1)) { number = static_cast(reader.readByte()); } switch(ilstChild.id()) { @@ -185,29 +183,29 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) // track number, disk number and genre have no specific data type id case TrackPosition: case DiskPosition: { - if(dataAtom->totalSize() < (16 + 6)) { + if(dataAtom->dataSize() < (8 + 6)) { addNotification(NotificationType::Warning, "Track/disk position is truncated. Trying to read data anyways.", context); } uint16 pos = 0, total = 0; - if(dataAtom->totalSize() >= (16 + 4)) { + if(dataAtom->dataSize() >= (8 + 4)) { stream.seekg(2, ios_base::cur); pos = reader.readUInt16BE(); } - if(dataAtom->totalSize() >= (16 + 6)) { + if(dataAtom->dataSize() >= (8 + 6)) { total = reader.readUInt16BE(); } value().assignPosition(PositionInSet(pos, total)); break; } case PreDefinedGenre: - if(dataAtom->totalSize() < (16 + 2)) { + if(dataAtom->dataSize() < (8 + 2)) { addNotification(NotificationType::Warning, "Genre index is truncated.", context); } else { value().assignStandardGenreIndex(reader.readUInt16BE() - 1); } break; default: // no supported data type, read raw data - streamsize dataSize = dataAtom->totalSize() - 16; + streamsize dataSize = dataAtom->dataSize() - 8; unique_ptr data = make_unique(dataSize); stream.read(data.get(), dataSize); if(ilstChild.id() == Mp4TagAtomIds::Cover) { @@ -217,31 +215,35 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) } } } - } else if((dataAtom->id() == Mp4AtomIds::Mean) && (dataAtom->totalSize() > 12)) { - ++meanAtomFound; - if(meanAtomFound > 1) { - if(meanAtomFound == 2) + } else if(dataAtom->id() == Mp4AtomIds::Mean) { + if(dataAtom->dataSize() < 8) { + addNotification(NotificationType::Warning, "Truncated child atom \"mean\" in tag atom (ilst child) found. (will be ignored)", context); + continue; + } + if(++meanAtomFound > 1) { + if(meanAtomFound == 2) { addNotification(NotificationType::Warning, "Tag atom contains more than one mean atom. The addiational mean atoms will be ignored.", context); - dataAtom = dataAtom->nextSibling(); + } continue; } - stream.seekg(dataAtom->startOffset() + 12); - m_mean = reader.readString(dataAtom->totalSize() - 12); - } else if((dataAtom->id() == Mp4AtomIds::Name) && (dataAtom->totalSize() > 12)) { - ++nameAtomFound; - if(nameAtomFound > 1) { - if(nameAtomFound == 2) + stream.seekg(dataAtom->dataOffset() + 4); + m_mean = reader.readString(dataAtom->dataSize() - 4); + } else if(dataAtom->id() == Mp4AtomIds::Name) { + if(dataAtom->dataSize() < 4) { + addNotification(NotificationType::Warning, "Truncated child atom \"name\" in tag atom (ilst child) found. (will be ignored)", context); + continue; + } + if(++nameAtomFound > 1) { + if(nameAtomFound == 2) { addNotification(NotificationType::Warning, "Tag atom contains more than one name atom. The addiational name atoms will be ignored.", context); - dataAtom = dataAtom->nextSibling(); + } continue; } - stream.seekg(dataAtom->startOffset() + 12); - m_name = reader.readString(dataAtom->totalSize() - 12); + stream.seekg(dataAtom->dataOffset() + 4); + m_name = reader.readString(dataAtom->dataSize() - 4); } else { addNotification(NotificationType::Warning, "Unkown child atom \"" + dataAtom->idToString() + "\" in tag atom (ilst child) found. (will be ignored)", context); } - - dataAtom = dataAtom->nextSibling(); } catch(Failure &) { addNotification(NotificationType::Warning, "Unable to parse all childs atom in tag atom (ilst child) found. (will be ignored)", context); } diff --git a/mp4/mp4track.cpp b/mp4/mp4track.cpp index bcc4a2f..fa36bee 100644 --- a/mp4/mp4track.cpp +++ b/mp4/mp4track.cpp @@ -1050,7 +1050,7 @@ void Mp4Track::makeSampleTable() void Mp4Track::internalParseHeader() { - const string context("parsing MP4 track"); + static const string context("parsing MP4 track"); using namespace Mp4AtomIds; if(!m_trakAtom) { addNotification(NotificationType::Critical, "Trak atom is null.", context); @@ -1058,59 +1058,43 @@ void Mp4Track::internalParseHeader() } // get atoms try { - m_tkhdAtom = m_trakAtom->childById(TrackHeader); - if(!m_tkhdAtom) { + if(!(m_tkhdAtom = m_trakAtom->childById(TrackHeader))) { addNotification(NotificationType::Critical, "No tkhd atom found.", context); throw InvalidDataException(); } - m_mdiaAtom = m_trakAtom->childById(Media); - if(!m_mdiaAtom) { + if(!(m_mdiaAtom = m_trakAtom->childById(Media))) { addNotification(NotificationType::Critical, "No mdia atom found.", context); throw InvalidDataException(); } - m_mdhdAtom = m_mdiaAtom->childById(MediaHeader); - if(!m_mdhdAtom) { + if(!(m_mdhdAtom = m_mdiaAtom->childById(MediaHeader))) { addNotification(NotificationType::Critical, "No mdhd atom found.", context); throw InvalidDataException(); } - m_hdlrAtom = m_mdiaAtom->childById(HandlerReference); - if(!m_hdlrAtom) { + if(!(m_hdlrAtom = m_mdiaAtom->childById(HandlerReference))) { addNotification(NotificationType::Critical, "No hdlr atom found.", context); throw InvalidDataException(); } - m_minfAtom = m_mdiaAtom->childById(MediaInformation); - if(!m_minfAtom) { + if(!(m_minfAtom = m_mdiaAtom->childById(MediaInformation))) { addNotification(NotificationType::Critical, "No minf atom found.", context); throw InvalidDataException(); } - m_stblAtom = m_minfAtom->childById(SampleTable); - if(!m_stblAtom) { + if(!(m_stblAtom = m_minfAtom->childById(SampleTable))) { addNotification(NotificationType::Critical, "No stbl atom found.", context); throw InvalidDataException(); } - m_stsdAtom = m_stblAtom->childById(SampleDescription); - if(!m_stsdAtom) { + if(!(m_stsdAtom = m_stblAtom->childById(SampleDescription))) { addNotification(NotificationType::Critical, "No stsd atom found.", context); throw InvalidDataException(); } - m_stcoAtom = m_stblAtom->childById(ChunkOffset); - if(!m_stcoAtom) { - m_stblAtom->childById(ChunkOffset64); - } - if(!m_stcoAtom) { + if(!(m_stcoAtom = m_stblAtom->childById(ChunkOffset)) && !(m_stcoAtom = m_stblAtom->childById(ChunkOffset64))) { addNotification(NotificationType::Critical, "No stco/co64 atom found.", context); throw InvalidDataException(); } - m_stscAtom = m_stblAtom->childById(SampleToChunk); - if(!m_stscAtom) { + if(!(m_stscAtom = m_stblAtom->childById(SampleToChunk))) { addNotification(NotificationType::Critical, "No stsc atom found.", context); throw InvalidDataException(); } - m_stszAtom = m_stblAtom->childById(SampleSize); - if(!m_stszAtom) { - m_stszAtom = m_stblAtom->childById(CompactSampleSize); - } - if(!m_stszAtom) { + if(!(m_stszAtom = m_stblAtom->childById(SampleSize)) && !(m_stszAtom = m_stblAtom->childById(CompactSampleSize))) { addNotification(NotificationType::Critical, "No stsz/stz2 atom found.", context); throw InvalidDataException(); } @@ -1206,7 +1190,7 @@ void Mp4Track::internalParseHeader() codecConfigContainerAtom->parse(); // parse FOURCC m_formatId = interpretIntegerAsString(codecConfigContainerAtom->id()); - m_format = Mp4FormatIds::fourccToMediaFormat(codecConfigContainerAtom->id()); + m_format = FourccIds::fourccToMediaFormat(codecConfigContainerAtom->id()); // parse AVC configuration //codecConfigContainerAtom->childById(Mp4AtomIds::AvcConfiguration); // parse MPEG-4 elementary stream descriptor diff --git a/tagparser.pro b/tagparser.pro index aca4c60..7d8aae8 100644 --- a/tagparser.pro +++ b/tagparser.pro @@ -69,7 +69,6 @@ SOURCES += \ mediaformat.cpp \ avc/avcconfiguration.cpp \ mp4/mpeg4descriptor.cpp \ - avi/mediafourcc.cpp \ avi/bitmapinfoheader.cpp HEADERS += \ @@ -137,7 +136,6 @@ HEADERS += \ avc/avcconfiguration.h \ generictagfield.h \ mp4/mpeg4descriptor.h \ - avi/mediafourcc.h \ avi/bitmapinfoheader.h LIBS += -lz @@ -163,7 +161,7 @@ INCLUDEPATH += ../ # installs target.path = $$(INSTALL_ROOT)/lib INSTALLS += target -for(dir, $$list(./ avc id3 matroska mp4 mpegaudio ogg vorbis wav)) { +for(dir, $$list(./ avc id3 matroska mp4 mpegaudio ogg vorbis wav avi)) { eval(inc_$${dir} = $${dir}) inc_$${dir}.path = $$(INSTALL_ROOT)/include/$$projectname/$${dir} inc_$${dir}.files = $${dir}/*.h diff --git a/wav/waveaudiostream.cpp b/wav/waveaudiostream.cpp index 356e164..b9a0faf 100644 --- a/wav/waveaudiostream.cpp +++ b/wav/waveaudiostream.cpp @@ -3,10 +3,56 @@ #include "../exceptions.h" #include "../mediaformat.h" +#include + using namespace std; namespace Media { +/*! + * \class Media::WaveFormatHeader + * \brief The WaveFormatHeader class parses the WAVEFORMATEX structure defined by MS. + */ + +/*! + * \brief Constructs a new WaveFormatHeader. + */ +WaveFormatHeader::WaveFormatHeader() : + formatTag(0), + channelCount(0), + sampleRate(0), + bytesPerSecond(0), + chunkSize(0), + bitsPerSample(0) +{} + +/*! + * \brief Parses the WAVE header using the specified \a reader. + * \remarks Reads 16 bytes from the associated stream. + */ +void WaveFormatHeader::parse(IoUtilities::BinaryReader &reader) +{ + formatTag = reader.readUInt16LE(); + channelCount = reader.readUInt16LE(); + sampleRate = reader.readUInt32LE(); + bytesPerSecond = reader.readUInt32LE(); + chunkSize = reader.readUInt16LE(); + bitsPerSample = reader.readUInt16LE(); +} + +/*! + * \brief Returns the media format denoted by the format tag. + */ +MediaFormat WaveFormatHeader::format() const +{ + switch(formatTag) { + case 0x0001u: return GeneralMediaFormat::Pcm; + case 0x0050u: return MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer2); + case 0x0055u: return MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer3); + default: return GeneralMediaFormat::Unknown; + } +} + /*! * \class Media::WaveAudioStream * \brief Implementation of Media::AbstractTrack for the @@ -33,6 +79,20 @@ TrackType WaveAudioStream::type() const return TrackType::WaveAudioStream; } +/*! + * \brief Adds the information from the specified \a waveHeader to the specified \a track. + */ +void WaveAudioStream::addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track) +{ + track.m_format = waveHeader.format(); + track.m_channelCount = waveHeader.channelCount; + track.m_sampleRate = waveHeader.sampleRate; + track.m_bytesPerSecond = waveHeader.bytesPerSecond; + track.m_chunkSize = waveHeader.chunkSize; + track.m_bitsPerSample = waveHeader.bitsPerSample; + track.m_bitrate = waveHeader.bitrate(); +} + void WaveAudioStream::internalParseHeader() { if(!m_istream) { @@ -44,27 +104,9 @@ void WaveAudioStream::internalParseHeader() uint32 restHeaderLen = m_reader.readUInt32LE(); m_dataOffset = static_cast(m_istream->tellg()) + static_cast(restHeaderLen); if(restHeaderLen >= 16u) { - switch(m_reader.readUInt16LE()) { - case 0x0001u: - m_format = GeneralMediaFormat::Pcm; - break; - case 0x0050u: - m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer2); - break; - case 0x0055u: - m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer3); - break; - default: - m_format = GeneralMediaFormat::Unknown; - } - m_channelCount = m_reader.readUInt16LE(); - m_sampleRate = m_reader.readUInt32LE(); - m_bytesPerSecond = m_reader.readUInt32LE(); - m_chunkSize = m_reader.readUInt16LE(); - m_bitsPerSample = m_reader.readUInt16LE(); - m_bitrate = m_bitsPerSample * m_sampleRate * m_channelCount; - } else { - m_format = GeneralMediaFormat::Unknown; + WaveFormatHeader waveHeader; + waveHeader.parse(m_reader); + addInfo(waveHeader, *this); } if(restHeaderLen > 16u) { m_istream->seekg(m_dataOffset, ios_base::beg); diff --git a/wav/waveaudiostream.h b/wav/waveaudiostream.h index 6823aa5..ac0e01f 100644 --- a/wav/waveaudiostream.h +++ b/wav/waveaudiostream.h @@ -3,13 +3,36 @@ #include "../abstracttrack.h" -#include - #include namespace Media { +class LIB_EXPORT WaveFormatHeader +{ +public: + WaveFormatHeader(); + + void parse(IoUtilities::BinaryReader &reader); + MediaFormat format() const; + uint32 bitrate() const; + + uint16 formatTag; + uint16 channelCount; + uint16 sampleRate; + uint16 bytesPerSecond; + uint16 chunkSize; + uint16 bitsPerSample; +}; + +/*! + * \brief Calculates the bitrate from the header data. + */ +inline uint32 WaveFormatHeader::bitrate() const +{ + return bitsPerSample * sampleRate * channelCount; +} + class LIB_EXPORT WaveAudioStream : public AbstractTrack { public: @@ -18,6 +41,8 @@ public: virtual TrackType type() const; + static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track); + protected: virtual void internalParseHeader();