diff --git a/abstracttrack.cpp b/abstracttrack.cpp index 2226ed7..0cc4d17 100644 --- a/abstracttrack.cpp +++ b/abstracttrack.cpp @@ -78,28 +78,6 @@ AbstractTrack::AbstractTrack(iostream &stream, uint64 startOffset) : AbstractTrack::~AbstractTrack() {} -/*! - * \brief Returns the format of the track as C-style string if known; otherwise - * returns the format abbreviation or an empty string. - * \remarks - * - The caller must not free the returned string. - * - The string might get invalidated when the track is (re)parsed. - */ -const char *AbstractTrack::formatName() const -{ - return m_format || m_formatName.empty() ? m_format.name() : m_formatName.c_str(); -} - -/*! - * \brief Returns the a more or less common abbreviation for the format of the track - * as C-style string if known; otherwise returns an empty string. - */ -const char *AbstractTrack::formatAbbreviation() const -{ - const char *abbr = m_format.abbreviation(); - return *abbr || m_formatId.empty() ? m_format.abbreviation() : m_formatId.c_str(); -} - /*! * \brief Returns the media type as string. */ diff --git a/abstracttrack.h b/abstracttrack.h index 7de644a..d636414 100644 --- a/abstracttrack.h +++ b/abstracttrack.h @@ -54,6 +54,7 @@ public: double version() const; const char *formatName() const; const char *formatAbbreviation() const; + const std::string &formatId() const; MediaType mediaType() const; const char *mediaTypeName() const; uint64 size() const; @@ -239,6 +240,37 @@ inline double AbstractTrack::version() const return m_version; } +/*! + * \brief Returns the format of the track as C-style string if known; otherwise + * returns the format abbreviation or an empty string. + * \remarks + * - The caller must not free the returned string. + * - The string might get invalidated when the track is (re)parsed. + */ +inline const char *AbstractTrack::formatName() const +{ + return m_format || m_formatName.empty() ? m_format.name() : m_formatName.c_str(); +} + +/*! + * \brief Returns the a more or less common abbreviation for the format of the track + * as C-style string if known; otherwise returns an empty string. + */ +inline const char *AbstractTrack::formatAbbreviation() const +{ + const char *abbr = m_format.abbreviation(); + return *abbr || m_formatId.empty() ? m_format.abbreviation() : m_formatId.c_str(); +} + +/*! + * \brief Returns the format ID (raw format identifier directly extracted from + * the container) if known; otherwise returns an empty string. + */ +inline const std::string &AbstractTrack::formatId() const +{ + return m_formatId; +} + /*! * \brief Returns the media type if known; otherwise returns MediaType::Other. */ diff --git a/avi/bitmapinfoheader.cpp b/avi/bitmapinfoheader.cpp new file mode 100644 index 0000000..8afb71b --- /dev/null +++ b/avi/bitmapinfoheader.cpp @@ -0,0 +1,51 @@ +#include "bitmapinfoheader.h" + +#include + +using namespace IoUtilities; + +namespace Media { + +/*! + * \class Media::BitmapInfoHeader + * \brief The BitmapInfoHeader class parses the BITMAPINFOHEADER structure defined by MS. + */ + +/*! + * \brief Constructs a new BitmapInfoHeader. + */ +BitmapInfoHeader::BitmapInfoHeader() : + size(0), + width(0), + height(0), + planes(0), + bitCount(0), + compression(0), + imageSize(0), + horizontalResolution(0), + verticalResolution(0), + clrUsed(0), + clrImportant(0) +{} + +/*! + * \brief Parses the BITMAPINFOHEADER structure using the specified \a reader. + * \remarks 0x28 byte will be read from the associated stream. + */ +void BitmapInfoHeader::parse(BinaryReader &reader) +{ + size = reader.readUInt32LE(); + width = reader.readUInt32LE(); + height = reader.readUInt32LE(); + planes = reader.readUInt16LE(); + bitCount = reader.readUInt16LE(); + compression = reader.readUInt32BE(); + imageSize = reader.readUInt32LE(); + horizontalResolution = reader.readUInt32LE(); + verticalResolution = reader.readUInt32LE(); + clrUsed = reader.readUInt32LE(); + clrImportant = reader.readUInt32LE(); +} + +} // namespace Media + diff --git a/avi/bitmapinfoheader.h b/avi/bitmapinfoheader.h new file mode 100644 index 0000000..ba633f7 --- /dev/null +++ b/avi/bitmapinfoheader.h @@ -0,0 +1,35 @@ +#ifndef MEDIA_BITMAPINFOHEADER_H +#define MEDIA_BITMAPINFOHEADER_H + +#include +#include + +namespace IoUtilities { +class BinaryReader; +} + +namespace Media { + +class LIB_EXPORT BitmapInfoHeader +{ +public: + BitmapInfoHeader(); + + void parse(IoUtilities::BinaryReader &reader); + + uint32 size; + uint32 width; + uint32 height; + uint16 planes; + uint16 bitCount; + uint32 compression; + uint32 imageSize; + uint32 horizontalResolution; + uint32 verticalResolution; + uint32 clrUsed; + uint32 clrImportant; +}; + +} // namespace Media + +#endif // MEDIA_BITMAPINFOHEADER_H diff --git a/avi/mediafourcc.cpp b/avi/mediafourcc.cpp new file mode 100644 index 0000000..e8cc820 --- /dev/null +++ b/avi/mediafourcc.cpp @@ -0,0 +1,19 @@ +#include "mediafourcc.h" + +#include "../mediaformat.h" + +namespace Media { + +namespace Fourccs { + +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 new file mode 100644 index 0000000..be3ae7b --- /dev/null +++ b/avi/mediafourcc.h @@ -0,0 +1,354 @@ +#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/matroska/matroskatrack.cpp b/matroska/matroskatrack.cpp index aa8c3e5..7de4489 100644 --- a/matroska/matroskatrack.cpp +++ b/matroska/matroskatrack.cpp @@ -3,6 +3,9 @@ #include "matroskacontainer.h" #include "matroskaid.h" +#include "../avi/bitmapinfoheader.h" +#include "../avi/mediafourcc.h" + #include "../mediaformat.h" #include "../exceptions.h" @@ -60,7 +63,7 @@ MediaFormat MatroskaTrack::codecIdToMediaFormat(const string &codecId) fmt.sub = SubFormats::Mpeg4Sp; } else if(part3 == "ASP") { fmt.sub = SubFormats::Mpeg4Asp; - } else if(part3 == "AP") { + } else if(part3 == "AVC") { fmt.sub = SubFormats::Mpeg4Avc; } } else if(part2 == "MS" && part3 == "V3") { @@ -181,17 +184,15 @@ MediaFormat MatroskaTrack::codecIdToMediaFormat(const string &codecId) void MatroskaTrack::internalParseHeader() { - const string context("parsing header of Matroska track"); - + static const string context("parsing header of Matroska track"); try { m_trackElement->parse(); } catch(Failure &) { addNotification(NotificationType::Critical, "Unable to parse track element.", context); throw; } - - EbmlElement *trackInfoElement = m_trackElement->firstChild(), *subElement = nullptr; - while(trackInfoElement) { + // read information about the track from the childs of the track entry element + for(EbmlElement *trackInfoElement = m_trackElement->firstChild(), *subElement = nullptr; trackInfoElement; trackInfoElement = trackInfoElement->nextSibling()) { try { trackInfoElement->parse(); } catch (Failure &) { @@ -258,7 +259,8 @@ void MatroskaTrack::internalParseHeader() case MatroskaIds::ColorSpace: m_colorSpace = subElement->readUInteger(); break; - default: ; + default: + ; } subElement = subElement->nextSibling(); } @@ -282,7 +284,8 @@ void MatroskaTrack::internalParseHeader() case MatroskaIds::SamplingFrequency: m_sampleRate = subElement->readFloat(); break; - default: ; + default: + ; } subElement = subElement->nextSibling(); } @@ -308,6 +311,8 @@ void MatroskaTrack::internalParseHeader() case MatroskaIds::CodecName: m_formatName = trackInfoElement->readString(); break; + case MatroskaIds::CodecDelay: + break; // TODO case MatroskaIds::TrackFlagEnabled: m_enabled = trackInfoElement->readUInteger(); break; @@ -323,7 +328,8 @@ void MatroskaTrack::internalParseHeader() case MatroskaIds::DefaultDuration: defaultDuration = trackInfoElement->readUInteger(); break; - default: ; + default: + ; } switch(m_mediaType) { case MediaType::Video: @@ -331,10 +337,33 @@ void MatroskaTrack::internalParseHeader() m_fps = 1000000000.0 / static_cast(defaultDuration); } break; - default: ; + default: + ; } - - trackInfoElement = trackInfoElement->nextSibling(); + } + // read further information from the CodecPrivate element for some codecs + 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) { + m_istream->seekg(codecPrivateElement->dataOffset()); + BitmapInfoHeader bitmapInfoHeader; + bitmapInfoHeader.parse(reader()); + m_formatId.reserve(m_formatId.size() + 7); + m_formatId += " \""; + m_formatId += interpretIntegerAsString(bitmapInfoHeader.compression); + m_formatId += "\""; + m_format += Fourccs::fourccToMediaFormat(bitmapInfoHeader.compression); + } else { + addNotification(NotificationType::Critical, "BITMAPINFOHEADER structure (in \"CodecPrivate\"-element) is truncated.", context); + } + } + break; + default: + ; } } diff --git a/tagparser.pro b/tagparser.pro index ceb164f..aca4c60 100644 --- a/tagparser.pro +++ b/tagparser.pro @@ -68,7 +68,9 @@ SOURCES += \ matroska/matroskaattachment.cpp \ mediaformat.cpp \ avc/avcconfiguration.cpp \ - mp4/mpeg4descriptor.cpp + mp4/mpeg4descriptor.cpp \ + avi/mediafourcc.cpp \ + avi/bitmapinfoheader.cpp HEADERS += \ abstractcontainer.h \ @@ -134,7 +136,9 @@ HEADERS += \ mediaformat.h \ avc/avcconfiguration.h \ generictagfield.h \ - mp4/mpeg4descriptor.h + mp4/mpeg4descriptor.h \ + avi/mediafourcc.h \ + avi/bitmapinfoheader.h LIBS += -lz