diff options
author | povaddict <povaddict@users.sourceforge.net> | 2010-02-10 02:16:44 +0300 |
---|---|---|
committer | povaddict <povaddict@users.sourceforge.net> | 2010-02-10 02:16:44 +0300 |
commit | 726a91b12a7524e45e7a901c9e4883af5b1bffe6 (patch) | |
tree | f5d25e3b2e84c92f4901280c73d5d3d7e6c3cd19 /src/filters/parser/MP4Splitter/AP4 | |
parent | 02183f6e47ad4ea1057de9950482f291f2ae4290 (diff) |
Rename several directories to use MixedCase instead of lowercase.
They now mostly match the case used in #includes,
and they're consistent with the names of the .h files they contain.
git-svn-id: https://mpc-hc.svn.sourceforge.net/svnroot/mpc-hc/trunk@1648 10f7b99b-c216-0410-bff0-8a66a9350fd8
Diffstat (limited to 'src/filters/parser/MP4Splitter/AP4')
222 files changed, 45685 insertions, 0 deletions
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AdtsParser.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AdtsParser.cpp new file mode 100644 index 000000000..1e46bbcee --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AdtsParser.cpp @@ -0,0 +1,319 @@ +/***************************************************************** +| +| AP4 - AAC ADTS Parser +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4BitStream.h" +#include "Ap4AdtsParser.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define AP4_ADTS_HEADER_SIZE 7 + +#define AP4_ADTS_SYNC_MASK 0xFFF6 /* 12 sync bits plus 2 layer bits */ +#define AP4_ADTS_SYNC_PATTERN 0xFFF0 /* 12 sync bits=1 layer=0 */ + +const unsigned long +AP4_AdtsSamplingFrequencyTable[16] = +{ + 96000, + 88200, + 64000, + 48000, + 44100, + 32000, + 24000, + 22050, + 16000, + 12000, + 11025, + 8000, + 7350, + 0, /* Reserved */ + 0, /* Reserved */ + 0 /* Escape code */ +}; + +/*----------------------------------------------------------------------+ +| AP4_AdtsHeader::AP4_AdtsHeader ++----------------------------------------------------------------------*/ +AP4_AdtsHeader::AP4_AdtsHeader(const AP4_UI08* bytes) +{ + // fixed part + m_Id = ( bytes[1] & 0x08) >> 3; + m_ProtectionAbsent = bytes[1] & 0x01; + m_ProfileObjectType = ( bytes[2] & 0xC0) >> 6; + m_SamplingFrequencyIndex = ( bytes[2] & 0x3C) >> 2; + m_ChannelConfiguration = ((bytes[2] & 0x01) << 2) | + ((bytes[3] & 0xC0) >> 6); + // variable part + m_FrameLength = ((unsigned int)(bytes[3] & 0x03) << 11) | + ((unsigned int)(bytes[4] ) << 3) | + ((unsigned int)(bytes[5] & 0xE0) >> 5); + m_RawDataBlocks = bytes[6] & 0x03; +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsHeader::MatchFixed +| +| Check that two fixed headers are the same +| ++----------------------------------------------------------------------*/ +bool +AP4_AdtsHeader::MatchFixed(unsigned char* a, unsigned char* b) +{ + if (a[0] == b[0] && + a[1] == b[1] && + a[2] == b[2] && + (a[3] & 0xF0) == (b[3] & 0xF0)) { + return true; + } else { + return false; + } +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsHeader::Check ++----------------------------------------------------------------------*/ +AP4_Result +AP4_AdtsHeader::Check() +{ + // check that the sampling frequency index is valid + if (m_SamplingFrequencyIndex >= 0xD) { + return AP4_FAILURE; + } + + /* MPEG2 does not use all profiles */ + if (m_Id == 1 && m_ProfileObjectType == 3) { + return AP4_FAILURE; + } + + return AP4_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::AP4_AdtsParser ++----------------------------------------------------------------------*/ +AP4_AdtsParser::AP4_AdtsParser() +{ +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::~AP4_AdtsParser ++----------------------------------------------------------------------*/ +AP4_AdtsParser::~AP4_AdtsParser() +{ +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::Reset ++----------------------------------------------------------------------*/ +AP4_Result +AP4_AdtsParser::Reset() +{ + m_FrameCount = 0; + + return AP4_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::Feed ++----------------------------------------------------------------------*/ +AP4_Result +AP4_AdtsParser::Feed(const AP4_UI08* buffer, + AP4_Size* buffer_size, + AP4_Flags flags) +{ + AP4_Size free_space; + + /* update flags */ + m_Bits.m_Flags = flags; + + /* possible shortcut */ + if (buffer == NULL || + buffer_size == NULL || + *buffer_size == 0) { + return AP4_SUCCESS; + } + + /* see how much data we can write */ + free_space = m_Bits.GetBytesFree(); + if (*buffer_size > free_space) *buffer_size = free_space; + + /* write the data */ + return m_Bits.WriteBytes(buffer, *buffer_size); +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::FindHeader ++----------------------------------------------------------------------*/ +AP4_Result +AP4_AdtsParser::FindHeader(AP4_UI08* header) +{ + int available = m_Bits.GetBytesAvailable(); + unsigned int sync = 0; + long nbr_skipped_bytes = 0; + + /* look for the sync pattern */ + while (available-- >= AP4_ADTS_HEADER_SIZE) { + sync = (m_Bits.ReadByte() << 8) | m_Bits.PeekByte(); + + if ((sync & AP4_ADTS_SYNC_MASK) == AP4_ADTS_SYNC_PATTERN) { + /* found a sync pattern, read the rest of the header */ + header[0] = (sync >> 8) & 0xFF; + m_Bits.ReadBytes(&header[1], AP4_ADTS_HEADER_SIZE-1); + + return AP4_SUCCESS; + } else { + ++ nbr_skipped_bytes; + } + } + + return AP4_ERROR_NOT_ENOUGH_DATA; +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::FindFrame ++----------------------------------------------------------------------*/ +AP4_Result +AP4_AdtsParser::FindFrame(AP4_AacFrame& frame) +{ + unsigned int available; + unsigned char raw_header[AP4_ADTS_HEADER_SIZE]; + AP4_Result result; + + /* align to the start of the next byte */ + m_Bits.ByteAlign(); + + /* find a frame header */ + result = FindHeader(raw_header); + if (AP4_FAILED(result)) return result; + + /* parse the header */ + AP4_AdtsHeader adts_header(raw_header); + + /* check the header */ + result = adts_header.Check(); + if (AP4_FAILED(result)) goto fail; + + /* check that we have enough data to peek at the next header */ + available = AP4_ADTS_HEADER_SIZE + m_Bits.GetBytesAvailable(); + if (m_Bits.m_Flags & AP4_BITSTREAM_FLAG_EOS) { + /* we're at the end of the stream, we only need the entire frame */ + if (available < adts_header.m_FrameLength) { + return AP4_ERROR_NOT_ENOUGH_DATA; + } + } else { + /* peek at the header of the next frame */ + unsigned char peek_raw_header[AP4_ADTS_HEADER_SIZE]; + + if (available < adts_header.m_FrameLength+AP4_ADTS_HEADER_SIZE) { + return AP4_ERROR_NOT_ENOUGH_DATA; + } + m_Bits.SkipBytes(adts_header.m_FrameLength-AP4_ADTS_HEADER_SIZE); + m_Bits.PeekBytes(peek_raw_header, AP4_ADTS_HEADER_SIZE); + m_Bits.SkipBytes(-((int)adts_header.m_FrameLength-AP4_ADTS_HEADER_SIZE)); + + /* check the header */ + AP4_AdtsHeader peek_adts_header(peek_raw_header); + result = peek_adts_header.Check(); + if (AP4_FAILED(result)) goto fail; + + /* check that the fixed part of this header is the same as the */ + /* fixed part of the previous header */ + if (!AP4_AdtsHeader::MatchFixed(peek_raw_header, raw_header)) { + goto fail; + } + } + + /* fill in the frame info */ + frame.m_Info.m_Standard = (adts_header.m_Id == 1 ? + AP4_AAC_STANDARD_MPEG2 : + AP4_AAC_STANDARD_MPEG4); + switch (adts_header.m_ProfileObjectType) { + case 0: + frame.m_Info.m_Profile = AP4_AAC_PROFILE_MAIN; + break; + + case 1: + frame.m_Info.m_Profile = AP4_AAC_PROFILE_LC; + break; + + case 2: + frame.m_Info.m_Profile = AP4_AAC_PROFILE_SSR; + break; + + case 3: + frame.m_Info.m_Profile = AP4_AAC_PROFILE_LTP; + } + frame.m_Info.m_FrameLength = adts_header.m_FrameLength-AP4_ADTS_HEADER_SIZE; + frame.m_Info.m_ChannelConfiguration = adts_header.m_ChannelConfiguration; + frame.m_Info.m_SamplingFrequencyIndex = adts_header.m_SamplingFrequencyIndex; + frame.m_Info.m_SamplingFrequency = AP4_AdtsSamplingFrequencyTable[adts_header.m_SamplingFrequencyIndex]; + + /* skip crc if present */ + if (adts_header.m_ProtectionAbsent == 0) { + m_Bits.SkipBits(16); + } + + /* set the frame source */ + frame.m_Source = &m_Bits; + + return AP4_SUCCESS; + +fail: + /* skip the header and return (only skip the first byte in */ + /* case this was a false header that hides one just after) */ + //m_Bits.SkipBytes(-(AP4_ADTS_HEADER_SIZE-1)); + return AP4_ERROR_CORRUPTED_BITSTREAM; +} + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::GetBytesFree ++----------------------------------------------------------------------*/ +AP4_Size +AP4_AdtsParser::GetBytesFree() +{ + return (m_Bits.GetBytesFree()); +} + + + +/*----------------------------------------------------------------------+ +| AP4_AdtsParser::GetBytesAvailable ++----------------------------------------------------------------------*/ +AP4_Size +AP4_AdtsParser::GetBytesAvailable() +{ + return (m_Bits.GetBytesAvailable()); +} + + + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AdtsParser.h b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AdtsParser.h new file mode 100644 index 000000000..1db5f27b4 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AdtsParser.h @@ -0,0 +1,122 @@ +/***************************************************************** +| +| AP4 - AAC ADTS Parser +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_ADTS_PARSER_H_ +#define _AP4_ADTS_PARSER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4BitStream.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +extern const unsigned long AP4_AdtsSamplingFrequencyTable[16]; + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +class AP4_AdtsHeader { +public: + // constructor + AP4_AdtsHeader(const AP4_UI08* bytes); + + // methods + AP4_Result Check(); + + // members + + // fixed part + unsigned int m_Id; + unsigned int m_ProtectionAbsent; + unsigned int m_ProfileObjectType; + unsigned int m_SamplingFrequencyIndex; + unsigned int m_ChannelConfiguration; + + // variable part + unsigned int m_FrameLength; + unsigned int m_RawDataBlocks; + + // class methods + static bool MatchFixed(unsigned char* a, unsigned char* b); +}; + +typedef enum { + AP4_AAC_STANDARD_MPEG2, + AP4_AAC_STANDARD_MPEG4 +} AP4_AacStandard; + +typedef enum { + AP4_AAC_PROFILE_MAIN, + AP4_AAC_PROFILE_LC, + AP4_AAC_PROFILE_SSR, + AP4_AAC_PROFILE_LTP +} AP4_AacProfile; + +typedef struct { + AP4_AacStandard m_Standard; + AP4_AacProfile m_Profile; + unsigned int m_SamplingFrequencyIndex; + unsigned long m_SamplingFrequency; + unsigned int m_ChannelConfiguration; + unsigned int m_FrameLength; +} AP4_AacFrameInfo; + +typedef struct { + AP4_BitStream* m_Source; + AP4_AacFrameInfo m_Info; +} AP4_AacFrame; + +class AP4_AdtsParser { +public: + // constructor and destructor + AP4_AdtsParser(); + virtual ~AP4_AdtsParser(); + + // methods + AP4_Result Reset(); + AP4_Result Feed(const AP4_UI08* buffer, + AP4_Size* buffer_size, + AP4_Flags flags = 0); + AP4_Result FindFrame(AP4_AacFrame& frame); + AP4_Result Skip(AP4_Size size); + AP4_Size GetBytesFree(); + AP4_Size GetBytesAvailable(); + +private: + // methods + AP4_Result FindHeader(AP4_UI08* header); + + // members + AP4_BitStream m_Bits; + AP4_Cardinal m_FrameCount; +}; + +#endif // _AP4_ADTS_PARSER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AvcParser.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AvcParser.cpp new file mode 100644 index 000000000..ad568459d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AvcParser.cpp @@ -0,0 +1,217 @@ +/***************************************************************** +| +| AP4 - AVC Parser +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4AvcParser.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_AvcParser::NaluTypeName ++---------------------------------------------------------------------*/ +const char* +AP4_AvcParser::NaluTypeName(unsigned int nalu_type) +{ + switch (nalu_type) { + case 0: return "Unspecified"; + case 1: return "Coded slice of a non-IDR picture"; + case 2: return "Coded slice data partition A"; + case 3: return "Coded slice data partition B"; + case 4: return "Coded slice data partition C"; + case 5: return "Coded slice of an IDR picture"; + case 6: return "Supplemental enhancement information (SEI)"; + case 7: return "Sequence parameter set"; + case 8: return "Picture parameter set"; + case 9: return "Access unit delimiter"; + case 10: return "End of sequence"; + case 11: return "End of stream"; + case 12: return "Filler data"; + case 13: return "Sequence parameter set extension"; + case 14: return "Prefix NAL unit in scalable extension"; + case 15: return "Subset sequence parameter set"; + case 19: return "Coded slice of an auxiliary coded picture without partitioning"; + case 20: return "Coded slice in scalable extension"; + default: return NULL; + } +} + +/*---------------------------------------------------------------------- +| AP4_AvcParser::PrimaryPicTypeName ++---------------------------------------------------------------------*/ +const char* +AP4_AvcParser::PrimaryPicTypeName(unsigned int primary_pic_type) +{ + switch (primary_pic_type) { + case 0: return "I"; + case 1: return "I, P"; + case 2: return "I, P, B"; + case 3: return "SI"; + case 4: return "SI, SP"; + case 5: return "I, SI"; + case 6: return "I, SI, P, SP"; + case 7: return "I, SI, P, SP, B"; + default: return NULL; + } +} + +/*---------------------------------------------------------------------- +| AP4_AvcParser::SliceTypeName ++---------------------------------------------------------------------*/ +const char* +AP4_AvcParser::SliceTypeName(unsigned int slice_type) +{ + switch (slice_type) { + case 0: return "P"; + case 1: return "B"; + case 2: return "I"; + case 3: return "SP"; + case 4: return "SI"; + case 5: return "P"; + case 6: return "B"; + case 7: return "I"; + case 8: return "SP"; + case 9: return "SI"; + default: return NULL; + } +} + +/*---------------------------------------------------------------------- +| AP4_AvcParser::AP4_AvcParser ++---------------------------------------------------------------------*/ +AP4_AvcParser::AP4_AvcParser() : + m_State(STATE_RESET), + m_ZeroTrail(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_AvcParser::Feed ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AvcParser::Feed(const void* data, + AP4_Size data_size, + AP4_Size& bytes_consumed, + const AP4_DataBuffer*& nalu, + bool is_eos) +{ + // default return values + nalu = NULL; + bytes_consumed = 0; + + // iterate the state machine + unsigned int data_offset; + unsigned int payload_start = 0; + unsigned int payload_end = 0; + bool found_nalu = false; + for (data_offset=0; data_offset<data_size && !found_nalu; data_offset++) { + unsigned char byte = ((const unsigned char*)data)[data_offset]; + switch (m_State) { + case STATE_RESET: + if (byte == 0) { + m_State = STATE_START_CODE_1; + } + break; + + case STATE_START_CODE_1: + if (byte == 0) { + m_State = STATE_START_CODE_2; + } else { + m_State = STATE_RESET; + } + break; + + case STATE_START_CODE_2: + if (byte == 0) break; + if (byte == 1) { + m_State = STATE_START_NALU; + } else { + m_State = STATE_RESET; + } + break; + + case STATE_START_NALU: + m_Buffer.SetDataSize(0); + m_ZeroTrail = 0; + payload_start = payload_end = data_offset; + m_State = STATE_IN_NALU; + // FALLTHROUGH + + case STATE_IN_NALU: + if (byte == 0) { + m_ZeroTrail++; + break; + } + if (m_ZeroTrail >= 2) { + if (byte == 1) { + found_nalu = true; + m_State = STATE_START_NALU; + } else { + payload_end += m_ZeroTrail+1; + } + } else { + payload_end += m_ZeroTrail+1; + } + m_ZeroTrail = 0; + break; + } + } + if (is_eos && m_State == STATE_IN_NALU && data_offset == data_size) { + found_nalu = true; + m_ZeroTrail = 0; + m_State = STATE_RESET; + } + if (payload_end > payload_start) { + AP4_Size current_payload_size = m_Buffer.GetDataSize(); + m_Buffer.SetDataSize(m_Buffer.GetDataSize()+(payload_end-payload_start)); + AP4_CopyMemory(((unsigned char *)m_Buffer.UseData())+current_payload_size, + ((const unsigned char*)data)+payload_start, + payload_end-payload_start); + } + + // compute how many bytes we have consumed + bytes_consumed = data_offset; + + // return the NALU if we found one + if (found_nalu) nalu = &m_Buffer; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AvcParser::Reset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AvcParser::Reset() +{ + m_State = STATE_RESET; + m_ZeroTrail = 0; + m_Buffer.SetDataSize(0); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AvcParser.h b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AvcParser.h new file mode 100644 index 000000000..ffb626c94 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4AvcParser.h @@ -0,0 +1,96 @@ +/***************************************************************** +| +| AP4 - AVC Parser +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_AVC_PARSER_H_ +#define _AP4_AVC_PARSER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Results.h" +#include "Ap4DataBuffer.h" + +/*---------------------------------------------------------------------- +| AP4_AvcParser ++---------------------------------------------------------------------*/ +class AP4_AvcParser { +public: + static const char* NaluTypeName(unsigned int nalu_type); + static const char* PrimaryPicTypeName(unsigned int primary_pic_type); + static const char* SliceTypeName(unsigned int slice_type); + + AP4_AvcParser(); + + /** + * Feed some data to the parser and look for the next NAL Unit. + * + * @param data: Pointer to the memory buffer with the data to feed. + * @param data_size: Size in bytes of the buffer pointed to by the + * data pointer. + * @param bytes_consumed: Number of bytes from the data buffer that were + * consumed and stored by the parser. + * @param nalu: Reference to a pointer to a buffer object that contains + * a NAL unit found in the previously fed data, or a NULL pointer if no + * NAL unit can be found so far. + * @param eos: Boolean flag that indicates if this buffer is the last + * buffer in the stream/file (End Of Stream). + * + * @result: AP4_SUCCESS is the call succeeds, or an error code if it + * fails. + * + * The caller must not feed the same data twice. When this method + * returns, the caller should inspect the value of bytes_consumed and + * advance the input stream source accordingly, such that the next + * buffer passed to this method will be exactly bytes_consumed bytes + * after what was passed in this call. + */ + AP4_Result Feed(const void* data, + AP4_Size data_size, + AP4_Size& bytes_consumed, + const AP4_DataBuffer*& nalu, + bool eos=false); + + /** + * Reset the state of the parser (for example, to parse a new stream). + */ + AP4_Result Reset(); + +private: + enum { + STATE_RESET, + STATE_START_CODE_1, + STATE_START_CODE_2, + STATE_START_NALU, + STATE_IN_NALU + } m_State; + AP4_Cardinal m_ZeroTrail; + AP4_DataBuffer m_Buffer; +}; + +#endif // _AP4_AVC_PARSER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4BitStream.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4BitStream.cpp new file mode 100644 index 000000000..0e1ebd596 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4BitStream.cpp @@ -0,0 +1,268 @@ +/***************************************************************** +| +| AP4 - Bitstream Utility +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| For efficiency reasons, this bitstream library only handles +| data buffers that are a power of 2 in size ++---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4BitStream.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_BitStream::AP4_BitStream ++---------------------------------------------------------------------*/ +AP4_BitStream::AP4_BitStream() +{ + m_Buffer = new AP4_UI08[AP4_BITSTREAM_BUFFER_SIZE]; + Reset(); +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::~AP4_BitStream ++---------------------------------------------------------------------*/ +AP4_BitStream::~AP4_BitStream() +{ + delete[] m_Buffer; +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::Reset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_BitStream::Reset() +{ + m_In = 0; + m_Out = 0; + m_BitsCached = 0; + m_Cache = 0; + m_Flags = 0; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::ByteAlign ++---------------------------------------------------------------------*/ +AP4_Result +AP4_BitStream::ByteAlign() +{ + unsigned int to_flush = m_BitsCached & 7; + if (to_flush > 0) SkipBits(to_flush); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::GetContiguousBytesFree ++---------------------------------------------------------------------*/ +AP4_Size +AP4_BitStream::GetContiguousBytesFree() +{ + return + (m_In < m_Out) ? + (m_Out - m_In - 1) : + (m_Out == 0 ? (AP4_BITSTREAM_BUFFER_SIZE - m_In - 1) : + (AP4_BITSTREAM_BUFFER_SIZE - m_In)); +} + +/*---------------------------------------------------------------------- +| AP4_BitStream_GetBytesFree ++---------------------------------------------------------------------*/ +AP4_Size +AP4_BitStream::GetBytesFree() +{ + return + (m_In < m_Out) ? + (m_Out - m_In - 1) : + (AP4_BITSTREAM_BUFFER_SIZE + (m_Out - m_In) - 1); +} + +/*----------------------------------------------------------------------+ +| AP4_BitStream::WriteBytes ++----------------------------------------------------------------------*/ +AP4_Result +AP4_BitStream::WriteBytes(const AP4_UI08* bytes, + AP4_Size byte_count) +{ + /* check parameters */ + if (byte_count == 0) return AP4_SUCCESS; + if (bytes == NULL) return AP4_ERROR_INVALID_PARAMETERS; + + /* check that we have enough space */ + if (GetBytesFree() < byte_count) { + return AP4_FAILURE; + } + + /* write the bytes */ + if (m_In < m_Out) { + AP4_CopyMemory(m_Buffer+m_In, bytes, byte_count); + AP4_BITSTREAM_POINTER_ADD(m_In, byte_count); + } else { + unsigned int chunk = AP4_BITSTREAM_BUFFER_SIZE - m_In; + if (chunk > byte_count) chunk = byte_count; + + AP4_CopyMemory(m_Buffer+m_In, bytes, chunk); + AP4_BITSTREAM_POINTER_ADD(m_In, chunk); + + if (chunk != byte_count) { + AP4_CopyMemory(m_Buffer+m_In, + bytes+chunk, byte_count-chunk); + AP4_BITSTREAM_POINTER_ADD(m_In, byte_count-chunk); + } + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_BitStream_GetContiguousBytesAvailable ++---------------------------------------------------------------------*/ +AP4_Size +AP4_BitStream::GetContiguousBytesAvailable() +{ + return + (m_Out <= m_In) ? + (m_In - m_Out) : + (AP4_BITSTREAM_BUFFER_SIZE - m_Out); +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::GetBytesAvailable ++---------------------------------------------------------------------*/ +AP4_Size +AP4_BitStream::GetBytesAvailable() +{ + return + (m_Out <= m_In) ? + (m_In - m_Out) : + (m_In + (AP4_BITSTREAM_BUFFER_SIZE - m_Out)); +} + +/*----------------------------------------------------------------------+ +| AP4_BitStream::ReadBytes ++----------------------------------------------------------------------*/ +AP4_Result +AP4_BitStream::ReadBytes(AP4_UI08* bytes, + AP4_Size byte_count) +{ + if (byte_count == 0 || bytes == NULL) { + return AP4_ERROR_INVALID_PARAMETERS; + } + + /* Gets bytes from the cache */ + ByteAlign(); + while (m_BitsCached > 0 && byte_count > 0) { + *bytes = ReadBits(8); + ++ bytes; + -- byte_count; + } + + /* Get other bytes */ + if (byte_count > 0) { + if (m_Out < m_In) { + AP4_CopyMemory(bytes, m_Buffer + m_Out, byte_count); + AP4_BITSTREAM_POINTER_ADD(m_Out, byte_count); + } else { + unsigned int chunk = AP4_BITSTREAM_BUFFER_SIZE - m_Out; + if (chunk >= byte_count) chunk = byte_count; + + AP4_CopyMemory(bytes, m_Buffer+m_Out, chunk); + AP4_BITSTREAM_POINTER_ADD(m_Out, chunk); + + if (chunk != byte_count) { + AP4_CopyMemory(bytes+chunk, + m_Buffer+m_Out, + byte_count-chunk); + AP4_BITSTREAM_POINTER_ADD(m_Out, byte_count-chunk); + } + } + } + + return AP4_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| AP4_BitStream::PeekBytes ++----------------------------------------------------------------------*/ +AP4_Result +AP4_BitStream::PeekBytes(AP4_UI08* bytes, + AP4_Size byte_count) +{ + int bits_cached_byte; + + if (byte_count == 0 || bytes == NULL) { + return AP4_ERROR_INVALID_PARAMETERS; + } + + /* Gets bytes from the cache */ + bits_cached_byte = m_BitsCached & ~7; + while (bits_cached_byte > 0 && byte_count > 0) { + *bytes = (m_Cache >> bits_cached_byte) & 0xFF; + ++ bytes; + -- byte_count; + bits_cached_byte -= 8; + } + + /* Get other bytes */ + if (byte_count > 0) { + if (m_In > m_Out) { + AP4_CopyMemory(bytes, m_Buffer + m_Out, byte_count); + } else { + unsigned int out = m_Out; + unsigned int chunk = AP4_BITSTREAM_BUFFER_SIZE - out; + if (chunk >= byte_count) { + chunk = byte_count; + } + + AP4_CopyMemory(bytes, m_Buffer+out, chunk); + AP4_BITSTREAM_POINTER_ADD(out, chunk); + + if (chunk != byte_count) { + AP4_CopyMemory(bytes+chunk, + m_Buffer+out, + byte_count-chunk); + } + } + } + + return AP4_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| AP4_BitStream::SkipBytes ++----------------------------------------------------------------------*/ +AP4_Result +AP4_BitStream::SkipBytes(AP4_Size byte_count) +{ + AP4_BITSTREAM_POINTER_ADD(m_Out, byte_count); + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4BitStream.h b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4BitStream.h new file mode 100644 index 000000000..c0bb0566e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4BitStream.h @@ -0,0 +1,308 @@ +/***************************************************************** +| +| AP4 - Bitstream Utility +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_BIT_STREAM_H_ +#define _AP4_BIT_STREAM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Results.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int AP4_ERROR_BASE_BITSTREAM = -10000; + +// the max frame size we can handle +const unsigned int AP4_BITSTREAM_BUFFER_SIZE = 8192; + +// flags +#define AP4_BITSTREAM_FLAG_EOS 0x01 + +// error codes +const int AP4_ERROR_CORRUPTED_BITSTREAM = (AP4_ERROR_BASE_BITSTREAM - 0); +const int AP4_ERROR_NOT_ENOUGH_FREE_BUFFER = (AP4_ERROR_BASE_BITSTREAM - 1); + +/*---------------------------------------------------------------------- +| types helpers ++---------------------------------------------------------------------*/ +/* use long by default */ +typedef unsigned int AP4_BitsWord; +#define AP4_WORD_BITS 32 +#define AP4_WORD_BYTES 4 + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +class AP4_BitStream +{ +public: + // constructor and destructor + AP4_BitStream(); + ~AP4_BitStream(); + + // methods + AP4_Result Reset(); + AP4_Size GetContiguousBytesFree(); + AP4_Size GetBytesFree(); + AP4_Result WriteBytes(const AP4_UI08* bytes, AP4_Size byte_count); + AP4_Size GetContiguousBytesAvailable(); + AP4_Size GetBytesAvailable(); + AP4_UI08 ReadByte(); + AP4_Result ReadBytes(AP4_UI08* bytes, AP4_Size byte_count); + AP4_UI08 PeekByte(); + AP4_Result PeekBytes(AP4_UI08* bytes, AP4_Size byte_count); + int ReadBit(); + AP4_UI32 ReadBits(unsigned int bit_count); + int PeekBit(); + AP4_UI32 PeekBits(unsigned int bit_count); + AP4_Result SkipBytes(AP4_Size byte_count); + void SkipBit(); + void SkipBits(unsigned int bit_count); + AP4_Result ByteAlign(); + + // members + AP4_UI08* m_Buffer; + unsigned int m_In; + unsigned int m_Out; + AP4_BitsWord m_Cache; + unsigned int m_BitsCached; + unsigned int m_Flags; + +private: + // methods + AP4_BitsWord ReadCache() const; +}; + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define AP4_BIT_MASK(_n) ((1<<(_n))-1) + +#define AP4_BITSTREAM_POINTER_VAL(offset) \ + ((offset)&(AP4_BITSTREAM_BUFFER_SIZE-1)) + +#define AP4_BITSTREAM_POINTER_OFFSET(pointer, offset) \ + (AP4_BITSTREAM_POINTER_VAL((pointer)+(offset))) + +#define AP4_BITSTREAM_POINTER_ADD(pointer, offset) \ + ((pointer) = AP4_BITSTREAM_POINTER_OFFSET(pointer, offset)) + +/*---------------------------------------------------------------------- +| AP4_BitStream::ReadCache ++---------------------------------------------------------------------*/ +inline AP4_BitsWord +AP4_BitStream::ReadCache() const +{ + unsigned int pos = m_Out; + AP4_BitsWord cache; + +#if AP4_WORD_BITS != 32 +#error unsupported word size /* 64 and other word size not yet implemented */ +#endif + + if (pos <= AP4_BITSTREAM_BUFFER_SIZE - AP4_WORD_BYTES) { + unsigned char* out_ptr = &m_Buffer[pos]; + cache = (((AP4_BitsWord) out_ptr[0]) << 24) + | (((AP4_BitsWord) out_ptr[1]) << 16) + | (((AP4_BitsWord) out_ptr[2]) << 8) + | (((AP4_BitsWord) out_ptr[3]) ); + } else { + unsigned char* buf_ptr = m_Buffer; + cache = (((AP4_BitsWord) buf_ptr[ pos ]) << 24) + | (((AP4_BitsWord) buf_ptr[AP4_BITSTREAM_POINTER_OFFSET (pos, 1)]) << 16) + | (((AP4_BitsWord) buf_ptr[AP4_BITSTREAM_POINTER_OFFSET (pos, 2)]) << 8) + | (((AP4_BitsWord) buf_ptr[AP4_BITSTREAM_POINTER_OFFSET (pos, 3)]) ); + } + + return cache; +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::ReadBits ++---------------------------------------------------------------------*/ +inline AP4_UI32 +AP4_BitStream::ReadBits(unsigned int n) +{ + AP4_BitsWord result; + if (m_BitsCached >= n) { + /* we have enough bits in the cache to satisfy the request */ + m_BitsCached -= n; + result = (m_Cache >> m_BitsCached) & AP4_BIT_MASK(n); + } else { + /* not enough bits in the cache */ + AP4_BitsWord word; + + /* read the next word */ + { + word = ReadCache(); + m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES); + } + + /* combine the new word and the cache, and update the state */ + { + AP4_BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached); + n -= m_BitsCached; + m_BitsCached = AP4_WORD_BITS - n; + result = (word >> m_BitsCached) | (cache << n); + m_Cache = word; + } + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::ReadBit ++---------------------------------------------------------------------*/ +inline int +AP4_BitStream::ReadBit() +{ + AP4_BitsWord result; + if (m_BitsCached == 0) { + /* the cache is empty */ + + /* read the next word into the cache */ + m_Cache = ReadCache(); + m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES); + m_BitsCached = AP4_WORD_BITS - 1; + + /* return the first bit */ + result = m_Cache >> (AP4_WORD_BITS - 1); + } else { + /* get the bit from the cache */ + result = (m_Cache >> (--m_BitsCached)) & 1; + } + return result; +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::PeekBits ++---------------------------------------------------------------------*/ +inline AP4_UI32 +AP4_BitStream::PeekBits(unsigned int n) +{ + /* we have enough bits in the cache to satisfy the request */ + if (m_BitsCached >= n) { + return (m_Cache >> (m_BitsCached - n)) & AP4_BIT_MASK(n); + } else { + /* not enough bits in the cache, read the next word */ + AP4_BitsWord word = ReadCache(); + + /* combine the new word and the cache, and update the state */ + AP4_BitsWord cache = m_Cache & AP4_BIT_MASK(m_BitsCached); + n -= m_BitsCached; + return (word >> (AP4_WORD_BITS - n)) | (cache << n); + } +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::PeekBit ++---------------------------------------------------------------------*/ +inline int +AP4_BitStream::PeekBit() +{ + /* the cache is empty */ + if (m_BitsCached == 0) { + /* read the next word into the cache */ + AP4_BitsWord cache = ReadCache(); + + /* return the first bit */ + return cache >> (AP4_WORD_BITS - 1); + } else { + /* get the bit from the cache */ + return (m_Cache >> (m_BitsCached-1)) & 1; + } +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::SkipBits ++---------------------------------------------------------------------*/ +inline void +AP4_BitStream::SkipBits(unsigned int n) +{ + if (n <= m_BitsCached) { + m_BitsCached -= n; + } else { + n -= m_BitsCached; + while (n >= AP4_WORD_BITS) { + m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES); + n -= AP4_WORD_BITS; + } + if (n) { + m_Cache = ReadCache(); + m_BitsCached = AP4_WORD_BITS-n; + m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES); + } else { + m_BitsCached = 0; + m_Cache = 0; + } + } +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::SkipBit ++---------------------------------------------------------------------*/ +inline void +AP4_BitStream::SkipBit() +{ + if (m_BitsCached == 0) { + m_Cache = ReadCache(); + m_Out = AP4_BITSTREAM_POINTER_OFFSET(m_Out, AP4_WORD_BYTES); + m_BitsCached = AP4_WORD_BITS - 1; + } else { + --m_BitsCached; + } +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::ReadByte ++---------------------------------------------------------------------*/ +inline AP4_UI08 +AP4_BitStream::ReadByte() +{ + SkipBits(m_BitsCached & 7); + return ReadBits(8); +} + +/*---------------------------------------------------------------------- +| AP4_BitStream::PeekByte ++---------------------------------------------------------------------*/ +inline AP4_UI08 +AP4_BitStream::PeekByte() +{ + int extra_bits = m_BitsCached & 7; + int data = PeekBits(extra_bits + 8); + int byte = data & 0xFF; + + return byte; +} + +#endif // _AP4_BIT_STREAM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4Mp4AudioInfo.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4Mp4AudioInfo.cpp new file mode 100644 index 000000000..a054f0c97 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4Mp4AudioInfo.cpp @@ -0,0 +1,254 @@ +/***************************************************************** +| +| AP4 - AAC Info +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4BitStream.h" +#include "Ap4Mp4AudioInfo.h" +#include "Ap4DataBuffer.h" +#include "Ap4SampleDescription.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int AP4_AAC_MAX_SAMPLING_FREQUENCY_INDEX = 12; +static const unsigned int AP4_AacSamplingFreqTable[13] = +{ + 96000, 88200, 64000, 48000, + 44100, 32000, 24000, 22050, + 16000, 12000, 11025, 8000, + 7350 +}; + +/*---------------------------------------------------------------------- +| AP4_Mp4AudioDsiParser ++---------------------------------------------------------------------*/ +class AP4_Mp4AudioDsiParser +{ +public: + AP4_Mp4AudioDsiParser(const AP4_UI08* data, AP4_Size data_size) : + m_Data(data, data_size), + m_Position(0) {} + + AP4_Size BitsLeft() { return 8*m_Data.GetDataSize()-m_Position; } + AP4_UI32 ReadBits(unsigned int n) { + AP4_UI32 result = 0; + const AP4_UI08* data = m_Data.GetData(); + while (n) { + unsigned int bits_avail = 8-(m_Position%8); + unsigned int chunk_size = bits_avail >= n ? n : bits_avail; + unsigned int chunk_bits = (((unsigned int)(data[m_Position/8]))>>(bits_avail-chunk_size))&((1<<chunk_size)-1); + result = (result << chunk_size) | chunk_bits; + n -= chunk_size; + m_Position += chunk_size; + } + + return result; + } + +private: + AP4_DataBuffer m_Data; + unsigned int m_Position; +}; + +/*---------------------------------------------------------------------- +| AP4_Mp4AudioDecoderConfig::AP4_Mp4AudioDecoderConfig ++---------------------------------------------------------------------*/ +AP4_Mp4AudioDecoderConfig::AP4_Mp4AudioDecoderConfig() +{ + Reset(); +} + +/*---------------------------------------------------------------------- +| AP4_Mp4AudioDecoderConfig::Reset ++---------------------------------------------------------------------*/ +void +AP4_Mp4AudioDecoderConfig::Reset() +{ + m_ObjectType = 0; + m_SamplingFrequencyIndex = 0; + m_SamplingFrequency = 0; + m_ChannelCount = 0; + m_ChannelConfiguration = CHANNEL_CONFIG_NONE; + m_FrameLengthFlag = false; + m_DependsOnCoreCoder = false; + m_CoreCoderDelay = 0; + m_Extension.m_SbrPresent = false; + m_Extension.m_PsPresent = false; + m_Extension.m_ObjectType = 0; + m_Extension.m_SamplingFrequencyIndex = 0; + m_Extension.m_SamplingFrequency = 0; +} + +/*---------------------------------------------------------------------- +| AP4_Mp4AudioDecoderConfig::ParseAudioObjectType ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mp4AudioDecoderConfig::ParseAudioObjectType(AP4_Mp4AudioDsiParser& parser, AP4_UI08& object_type) +{ + if (parser.BitsLeft() < 5) return AP4_ERROR_INVALID_FORMAT; + object_type = (AP4_UI08)parser.ReadBits(5); + if ((int)object_type == 31) { + if (parser.BitsLeft() < 6) return AP4_ERROR_INVALID_FORMAT; + object_type = (AP4_UI08)(32 + parser.ReadBits(6)); + } + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mp4AudioDecoderConfig::ParseGASpecificInfo ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mp4AudioDecoderConfig::ParseGASpecificInfo(AP4_Mp4AudioDsiParser& parser) +{ + if (parser.BitsLeft() < 2) return AP4_ERROR_INVALID_FORMAT; + m_FrameLengthFlag = (parser.ReadBits(1) == 1); + m_DependsOnCoreCoder = (parser.ReadBits(1) == 1); + if (m_DependsOnCoreCoder) { + if (parser.BitsLeft() < 14) return AP4_ERROR_INVALID_FORMAT; + m_CoreCoderDelay = parser.ReadBits(14); + } else { + m_CoreCoderDelay = 0; + } + if (parser.BitsLeft() < 1) return AP4_ERROR_INVALID_FORMAT; + parser.ReadBits(1); /* extensionFlag */ + if (m_ChannelConfiguration == CHANNEL_CONFIG_NONE) { + /*program_config_element (); */ + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mp4AudioDecoderConfig::ParseSamplingFrequency ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mp4AudioDecoderConfig::ParseSamplingFrequency(AP4_Mp4AudioDsiParser& parser, + unsigned int& sampling_frequency_index, + unsigned int& sampling_frequency) +{ + if (parser.BitsLeft() < 4) { + return AP4_ERROR_INVALID_FORMAT; + } + + sampling_frequency_index = parser.ReadBits(4); + if (sampling_frequency_index == 0xF) { + if (parser.BitsLeft() < 24) { + return AP4_ERROR_INVALID_FORMAT; + } + sampling_frequency = parser.ReadBits(24); + } else if (sampling_frequency_index <= AP4_AAC_MAX_SAMPLING_FREQUENCY_INDEX) { + sampling_frequency = AP4_AacSamplingFreqTable[sampling_frequency_index]; + } else { + sampling_frequency = 0; + return AP4_ERROR_INVALID_FORMAT; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mp4AudioDecoderConfig::Parse ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mp4AudioDecoderConfig::Parse(const unsigned char* data, + AP4_Size data_size) +{ + AP4_Result result; + AP4_Mp4AudioDsiParser bits(data, data_size); + + // default config + Reset(); + + // parse the audio object type + result = ParseAudioObjectType(bits, m_ObjectType); + if (AP4_FAILED(result)) return result; + + // parse the sampling frequency + result = ParseSamplingFrequency(bits, + m_SamplingFrequencyIndex, + m_SamplingFrequency); + if (AP4_FAILED(result)) return result; + + if (bits.BitsLeft() < 4) { + return AP4_ERROR_INVALID_FORMAT; + } + m_ChannelConfiguration = (ChannelConfiguration)bits.ReadBits(4); + m_ChannelCount = (unsigned int)m_ChannelConfiguration; + if (m_ChannelCount == 7) { + m_ChannelCount = 8; + } else if (m_ChannelCount > 7) { + m_ChannelCount = 0; + } + + if (m_ObjectType == AP4_MPEG4_AUDIO_OBJECT_TYPE_SBR || + m_ObjectType == AP4_MPEG4_AUDIO_OBJECT_TYPE_PS) { + m_Extension.m_ObjectType = AP4_MPEG4_AUDIO_OBJECT_TYPE_SBR; + m_Extension.m_SbrPresent = true; + m_Extension.m_PsPresent = m_ObjectType == AP4_MPEG4_AUDIO_OBJECT_TYPE_PS; + result = ParseSamplingFrequency(bits, + m_Extension.m_SamplingFrequencyIndex, + m_Extension.m_SamplingFrequency); + if (AP4_FAILED(result)) return result; + result = ParseAudioObjectType(bits, m_ObjectType); + if (AP4_FAILED(result)) return result; + } else { + m_Extension.m_ObjectType = 0; + m_Extension.m_SamplingFrequency = 0; + m_Extension.m_SamplingFrequencyIndex = 0; + m_Extension.m_SbrPresent = false; + m_Extension.m_PsPresent = false; + } + + switch (m_ObjectType) { + case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_MAIN: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LC: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_SSR: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LTP: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_SCALABLE: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_TWINVQ: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LC: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LTP: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_SCALABLE: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LD: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_TWINVQ: + case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_BSAC: + result = ParseGASpecificInfo(bits); + break; + + default: + return AP4_ERROR_NOT_SUPPORTED; + } + + return AP4_SUCCESS; +} + + + + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4Mp4AudioInfo.h b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4Mp4AudioInfo.h new file mode 100644 index 000000000..eeb629069 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Codecs/Ap4Mp4AudioInfo.h @@ -0,0 +1,104 @@ +/***************************************************************** +| +| AP4 - MP4 Audio Info +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_MP4_AUDIO_INFO_H_ +#define _AP4_MP4_AUDIO_INFO_H_ + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_Mp4AudioDsiParser; + +/*---------------------------------------------------------------------- +| AP4_Mp4DecoderConfig ++---------------------------------------------------------------------*/ +/** + * Detailed AAC decoder configuration information. + * This information is necessary in order to create a decoder object. + * It is normally obtained from the DecoderSpecificInfo field of the + * DecoderConfigDescriptor descriptor carried in the sample description + * for the audio samples. See 14496-1, subpart 2, p 2.6.6 for details. + */ +class AP4_Mp4AudioDecoderConfig { +public: + /** + * Channel configuration for multichannel audio buffers. + */ + typedef enum { + CHANNEL_CONFIG_NONE = 0, /**< No channel (not used) */ + CHANNEL_CONFIG_MONO = 1, /**< Mono (single audio channel) */ + CHANNEL_CONFIG_STEREO = 2, /**< Stereo (Two audio channels) */ + CHANNEL_CONFIG_STEREO_PLUS_CENTER = 3, /**< Stereo plus one center channel */ + CHANNEL_CONFIG_STEREO_PLUS_CENTER_PLUS_REAR_MONO = 4, /**< Stereo plus one center and one read channel */ + CHANNEL_CONFIG_FIVE = 5, /**< Five channels */ + CHANNEL_CONFIG_FIVE_PLUS_ONE = 6, /**< Five channels plus one low frequency channel */ + CHANNEL_CONFIG_SEVEN_PLUS_ONE = 7, /**< Seven channels plus one low frequency channel */ + CHANNEL_CONFIG_UNSUPPORTED + } ChannelConfiguration; + + // constructor + AP4_Mp4AudioDecoderConfig(); + + /** + * Parser a DecoderSpecificInfo buffer + */ + AP4_Result Parse(const AP4_UI08* data, AP4_Size data_size); + + /** + * Reset all members to default values (0) + */ + void Reset(); + + // members + AP4_UI08 m_ObjectType; /**< Type identifier for the audio data */ + unsigned int m_SamplingFrequencyIndex; /**< Index of the sampling frequency in the sampling frequency table */ + unsigned int m_SamplingFrequency; /**< Sampling frequency */ + unsigned int m_ChannelCount; /**< Number of audio channels */ + ChannelConfiguration m_ChannelConfiguration; /**< Channel configuration */ + bool m_FrameLengthFlag; /**< Frame Length Flag */ + bool m_DependsOnCoreCoder; /**< Depends on Core Coder */ + unsigned int m_CoreCoderDelay; /**< Core Code delay */ + /** Extension details */ + struct { + bool m_SbrPresent; /**< SBR is present */ + bool m_PsPresent; /**< PS is present */ + AP4_UI08 m_ObjectType; /**< Extension object type */ + unsigned int m_SamplingFrequencyIndex; /**< Sampling frequency index of the extension */ + unsigned int m_SamplingFrequency; /**< Sampling frequency of the extension */ + } m_Extension; + +private: + AP4_Result ParseAudioObjectType(AP4_Mp4AudioDsiParser& parser, AP4_UI08& object_type); + AP4_Result ParseGASpecificInfo(AP4_Mp4AudioDsiParser& parser); + AP4_Result ParseSamplingFrequency(AP4_Mp4AudioDsiParser& parser, + unsigned int& sampling_frequency_index, + unsigned int& sampling_frequency); +}; + + +#endif // _AP4_MP4_AUDIO_INFO_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Config/Ap4Config.h b/src/filters/parser/MP4Splitter/AP4/Source/Config/Ap4Config.h new file mode 100644 index 000000000..b93154a10 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Config/Ap4Config.h @@ -0,0 +1,140 @@ +/*****************************************************************
+|
+| AP4 - Target Platform and Compiler Configuration
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+/**
+ * @file
+ * @brief Platform Configuration
+ */
+#ifndef _AP4_CONFIG_H_
+#define _AP4_CONFIG_H_
+
+/*----------------------------------------------------------------------
+| defaults
++---------------------------------------------------------------------*/
+#define AP4_CONFIG_HAVE_STDIO_H
+#define AP4_CONFIG_HAVE_ASSERT_H
+#define AP4_CONFIG_HAVE_STRING_H
+#define AP4_CONFIG_HAVE_SNPRINTF
+#define AP4_CONFIG_HAVE_VSNPRINTF
+#define AP4_CONFIG_HAVE_INT64
+
+/*----------------------------------------------------------------------
+| byte order
++---------------------------------------------------------------------*/
+// define AP4_PLATFORM_BYTE_ORDER to one of these two choices
+#define AP4_PLATFORM_BYTE_ORDER_BIG_ENDIAN 0
+#define AP4_PLATFORM_BYTE_ORDER_LITTLE_ENDIAN 1
+
+#if !defined(AP4_PLATFORM_BYTE_ORDER)
+#if defined(__ppc__)
+#define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_BIG_ENDIAN
+#else
+#define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_LITTLE_ENDIAN
+#endif
+#endif
+
+/*----------------------------------------------------------------------
+| standard C++ runtime
++---------------------------------------------------------------------*/
+#define APT_CONFIG_HAVE_NEW_H
+
+/*----------------------------------------------------------------------
+| platform specifics
++---------------------------------------------------------------------*/
+
+/* Microsoft Platforms */
+#if defined(_MSC_VER)
+#define AP4_CONFIG_INT64_TYPE __int64
+#if (_MSC_VER >= 1400) && !defined(_WIN32_WCE)
+#define AP4_CONFIG_HAVE_FOPEN_S
+#define AP4_snprintf(s,c,f,...) _snprintf_s(s,c,_TRUNCATE,f,__VA_ARGS__)
+#define AP4_vsnprintf(s,c,f,a) _vsnprintf_s(s,c,_TRUNCATE,f,a)
+#define fileno _fileno
+#define AP4_fseek _fseeki64
+#define AP4_ftell _ftelli64
+#else
+#define AP4_snprintf _snprintf
+#define AP4_vsnprintf _vsnprintf
+#endif
+#if defined(_WIN32_WCE)
+#define AP4_fseek fseek
+#define AP4_ftell ftell
+#endif
+#if defined(_DEBUG)
+#define _CRTDBG_MAP_ALLOC
+#endif
+#endif
+
+/* Cygwin */
+#if defined(__CYGWIN__)
+#define AP4_fseek fseek
+#define AP4_ftell ftell
+#endif
+
+/* Symbian */
+#if defined(__SYMBIAN32__)
+#undef APT_CONFIG_HAVE_NEW_H
+#include "e32std.h"
+/**
+ * Define the Platform byte order here
+ * for Symbian.
+ */
+#define AP4_PLATFORM_BYTE_ORDER AP4_PLATFORM_BYTE_ORDER_LITTLE_ENDIAN
+#define AP4_fseek fseek
+#define AP4_ftell ftell
+#define explicit
+#endif
+
+/* Android */
+#if defined(ANDROID)
+#define AP4_CONFIG_NO_RTTI
+#define AP4_CONFIG_NO_EXCEPTIONS
+#endif
+
+/*----------------------------------------------------------------------
+| defaults
++---------------------------------------------------------------------*/
+#if !defined(AP4_CONFIG_INT64_TYPE)
+#define AP4_CONFIG_INT64_TYPE long long
+#endif
+
+#if !defined(AP4_fseek)
+#define AP4_fseek fseeko
+#endif
+#if !defined(AP4_ftell)
+#define AP4_ftell ftello
+#endif
+
+/* some compilers (ex: MSVC 8) deprecate those, so we rename them */
+#if !defined(AP4_snprintf)
+#define AP4_snprintf snprintf
+#endif
+#if !defined(AP4_vsnprintf)
+#define AP4_vsnprintf vsnprintf
+#endif
+
+#endif // _AP4_CONFIG_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4.h new file mode 100644 index 000000000..aa81266d4 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4.h @@ -0,0 +1,300 @@ +/***************************************************************** +| +| AP4 - Main Header +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ +/** +* @file +* @brief Top Level include file +* +* Applications should only need to include that file, as it will +* include all the more specific include files required to use the API +*/ + +/** @mainpage Bento4 SDK +* +* @section intro_sec Introduction +* Bento4/AP4 is a C++ class library designed to read and write ISO-MP4 files. +* This format is defined in ISO/IEC 14496-12, 14496-14 and 14496-15. +* The format is a derivative of the Apple Quicktime file format. +* Because of that, Bento4 can be used to read and write a number of Quicktime files +* as well, even though some Quicktime specific features are not supported. +* In addition, Bento4 supports a number of extensions as defined in various +* other specifications. This includes some support for ISMA Encrytion and +* Decryption as defined in the ISMA E&A specification (http://www.isma.tv), +* OMA 2.0 PDCF Encryption and Decryption as defined in the OMA 2.0 PDCF +* specification (http://www.openmobilealliance.org) and iTunes compatible +* metadata. +* The SDK includes a number of command line tools, built using the class library, +* that serve as general purpose tools as well as examples of how to use the API. +* +* The SDK is designed to be cross-platform. The code is very portable; it can +* be compiled with any sufficiently modern C++ compiler. The code does not rely +* on any external library; all the code necessary to compile the SDK and its +* tools is included in the standard distribution. The standard distribution +* contains makefiles for unix-like operating systems, including Linux, project +* files for Microsoft Visual Studio, and an XCode project for MacOS X. There is +* also support for building the library with the SCons build system. +* +* @section building Building the SDK +* Building the SDK will produce a C++ class library and some command line tools. +* For the makefile-based configurations, 'make sdk' will produce an SDK +* directory layout with a bin/ lib/ and include/ subdirectories containing +* respectively the binaries, library and header files. +* +* @subsection build_win32 Windows +* Open the solution file Build/Targets/Build/Targets/x86-microsoft-win32-vs2005 +* Building the solution will build the class library and command line tools. +* The script Build/Targets/Build/Targets/x86-microsoft-win32-vs2005/make-sdk.sh +* will create the SDK directory structure as described above. +* +* @subsection build_linux Linux +* Go to Build/Targets/x86-unknown-linux or Build/Targets/<target-name> +* for any linux-based target, and use the 'make' +* command to build the library and tools, or 'make sdk' to build the SDK +* directory structure. +* +* @subsection build_cygwin Cygwin +* Go to Build/Targets/x86-unknown-cygwin and follow the same instructions as +* for the Linux platform. +* +* @subsection build_macos MacOS +* Use the XCode project file located under Build/Targets/ppc-apple-macosx +* +* @subsection build_scons Using SCons +* There is experimental support for building the SDK using the python-based +* SCons tool (http://www.scons.org). The top level configuration is located +* at the root of the SDK, and will output all the object files and binaries +* to a sub-directory under Build/SCons/Targets/<target-name>/<config-name>. +* +* @subsection build_others Other Platforms +* Other plaftorms can be built by adapting the makefiles for the generic +* gcc-based configurations. +* +* @section mp4_structure Structure of an MP4 file +* +* An MP4 file consists of a tree of atoms (also known as boxes). The atoms +* contain the information about the different media tracks for the file, as +* well as other information, such as metadata. +* The Bento4 class library parses files an constructs an in-memory representation +* of the atoms, and provides an API that is an abstraction layer for the +* way the information is actually encoded in those atoms. +* +* @section reading Reading Files +* +* The class #AP4_File represents all the information about an MP4 file. +* Internally, a tree of #AP4_Atom objects plus other helper objects holds +* the actual information. +* To create an instance of the class, the caller must pass a reference to +* an #AP4_ByteStream object that represents the file data storage. The SDK +* includes two subclasses of the abstract #AP4_ByteStream class: +* #AP4_FileByteStream for reading/writing disk-based files and +* #AP4_MemoryByteStream for working with in-memory file images. +* Once you have created an #AP4_File object, you can get to the media data by +* accessing the #AP4_Track objects of its #AP4_Movie (see #AP4_File::GetMovie). +* The #AP4_Track exposes the necessary methods for you to get the +* #AP4_SampleDescription (typically to initialize your decoder) and to get the +* #AP4_Sample objects from the track. +* These #AP4_Sample objects give you the meta information you need (such as +* timestamps) as well as the sample data that they point to. +* You can also explore the entire tree of atoms by calling #AP4_File::Inspect, +* passing an instance of #AP4_AtomInspector. #AP4_AtomInspector is an abstract +* base class for a visitor of the tree of #AP4_Atom objects. The SDK includes +* an concrete subclass, #AP4_PrintInspector, can be used to print out a text +* representation of the atoms as they are visited. See the Mp4Dump command line +* application for an example. +* +* @section writing Writing Files +* +* To create a new MP4 file, you first create an #AP4_SyntheticSampleTable +* sample table for each track in your file. You specify the sample description +* for the media samples in each track by calling #AP4_SyntheticSampleTable::AddSampleDescription +* with the description for the samples of that track. Samples can then be added +* to the sample table with the #AP4_SyntheticSampleTable::AddSample method. +* Once all the samples of all the tracks have been added to the sample tables, +* you can create an #AP4_Movie, and an #AP4_Track from each sample table, add the track +* to the movie, and finally create an #AP4_File from the movie object. +* Finally, the #AP4_File object can be serialized to a byte stream (such as an +* #AP4_FileByteStream) using the #AP4_FileWriter class. +* See the Aac2Mp4 application for an example. +* +* @section tracks Tracks +* +* The #AP4_Movie object of an #AP4_File has a list of #AP4_Track objects. Each +* #AP4_Track represents a media track in the file. From this object, you can +* obtain the type, duration, etc.. of the tracks. This object also provides +* access to the media samples in the track. Tracks are made up of media samples, +* stored in an 'mdat' atom (media data) and a sample table that provides all the +* information about the individual samples, such as size, timestamps, sample +* description, etc... Media samples are represented by #AP4_Sample objects. +* You can obtain a track's samples by calling the #AP4_Track::GetSample method. +* You can also directly read the payload of a media sample by calling the +* #AP4_Track::ReadSample method if you want to bypass the intermediate step of +* going through an #AP4_Sample object. +* The information about the samples in a track is represented by subclasses of +* the #AP4_SampleDescription class. The sample descriptions contain information +* about media-specific parameters, such as video resolution, audio sampling rates +* and others. +* See the Mp4Info and Mp42Aac command line applications as examples. +* +* @section advanced Advanced Topics +* +* @subsection factory Custom Atoms +* +* The SDK has built-in support for most of the standard atom types as defined +* in the spec. But an application may want to extend the library to support +* non-standard atom type, such as custom atoms whose definition is proprietary. +* The base class for all atoms is #AP4_Atom. Instances of subclasses of this class +* are created by the #AP4_AtomFactory object. The factory knows about all the +* #AP4_Atom subclasses included in the SDK, and maintains a list of +* #AP4_AtomFactory::TypeHandler type handlers. When the factory encounters an atom +* that is not one of the built-in atom type, it calls all the registered type +* handlers, in turn, until one of them accept to handle the type and create the +* corresponding atom. The custom atoms must be implemented as subclasses of +* #AP4_Atom and override at least the #AP4_Atom::WriteFields method. The custom +* atoms should also override #AP4_Atom::InspectFields if they want to provide +* meaningful information when inspected. +* +* @subsection tranformations Transformations +* The SDK provides support for transforming MP4 files. Transformations are useful +* to perform tasks such as editing (removing or adding atoms) and encryption or +* decryption. When the atom tree for the file changes, the entire file needs to +* change, because in most cases, the size of the 'moov' atom will change, and +* thus change the offset of the media samples in the 'mdat' atom. +* To facilitate this operation, the class #AP4_Processor provides the base +* functionality for managing all the updates to the sample tables. Subclasses +* of the #AP4_Processor class can override certain methods to carry out specific +* changes to the structure of the atom tree and/or the media samples. #AP4_Processor +* defines an abstract base class, #AP4_Processor::TrackHandler that defines the +* interface that specific track modification classes must implement. A subclass +* of #AP4_Processor may create such an #AP4_Processor::TrackHandler subclass instance +* when is #AP4_Processor::CreateTrackHandler is called for one of the tracks in the +* file. +* See the sample applications Mp4Edit, Mp4Encrpt and Mp4Decrypt as examples. +* +* @subsection encryption Encryption and Decryption +* +* The SDK has support for encrypting and decrypting tracks as specified by the +* ISMA Encryption and Authentication specification as well as OMA 2.0 and 2.1 DCF and PDCF. +* The supporting classes found in Ap4IsmaCryp.h and AP4_OmaDcf.h provide a subclass +* of #AP4_Processor for encrypting or decrypting entire files. +* The class #AP4_IsmaCipher and #AP4_OmaDcfSampleDecrypter implement the generic +* #AP4_SampleDecrypter interface that provides support for decrypting individual samples. +* The parameters necessary to instantiate an #AP4_IsmaCipher or an #AP4_OmaDcfSampleDecrypter +* can be retrieved from an encrypted track by accessing the track's sample descriptions, +* which are instances of the #AP4_ProtectedSampleDescription class. A more general factory +* method, #AP4_SampleDecrypter::Create can be called, passing an instance of +* #AP4_ProtectedSampleDescription and the cipher key, and the correct concrete class will +* automatically be instanciated based on the type of encryption that was used for the track. +* +* @subsection RTP Packets +* +* For files that contain hint tracks, the SDK provides support for generating +* RTP packets that can be used to stream the media using the RTP and RTSP protocols. +* See the application Mp4RtpHintInfo for an example of how to generate the create +* RTP packets from a file and generate the SDP information for the RTSP protocol. +*/ + +#ifndef _AP4_H_ +#define _AP4_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Config.h" +#include "Ap4Version.h" +#include "Ap4Types.h" +#include "Ap4Constants.h" +#include "Ap4Results.h" +#include "Ap4Debug.h" +#include "Ap4Utils.h" +#include "Ap4DynamicCast.h" +#include "Ap4FileByteStream.h" +#include "Ap4Movie.h" +#include "Ap4Track.h" +#include "Ap4File.h" +#include "Ap4FileWriter.h" +#include "Ap4FileCopier.h" +#include "Ap4HintTrackReader.h" +#include "Ap4Processor.h" +#include "Ap4MetaData.h" +#include "Ap4AtomFactory.h" +#include "Ap4SampleEntry.h" +#include "Ap4Sample.h" +#include "Ap4DataBuffer.h" +#include "Ap4SampleTable.h" +#include "Ap4SyntheticSampleTable.h" +#include "Ap4AtomSampleTable.h" +#include "Ap4FragmentSampleTable.h" +#include "Ap4UrlAtom.h" +#include "Ap4MoovAtom.h" +#include "Ap4MvhdAtom.h" +#include "Ap4MehdAtom.h" +#include "Ap4TrakAtom.h" +#include "Ap4TrexAtom.h" +#include "Ap4HdlrAtom.h" +#include "Ap4DrefAtom.h" +#include "Ap4TkhdAtom.h" +#include "Ap4MdhdAtom.h" +#include "Ap4StsdAtom.h" +#include "Ap4StscAtom.h" +#include "Ap4StcoAtom.h" +#include "Ap4StszAtom.h" +#include "Ap4EsdsAtom.h" +#include "Ap4SttsAtom.h" +#include "Ap4CttsAtom.h" +#include "Ap4StssAtom.h" +#include "Ap4FtypAtom.h" +#include "Ap4VmhdAtom.h" +#include "Ap4SmhdAtom.h" +#include "Ap4NmhdAtom.h" +#include "Ap4HmhdAtom.h" +#include "Ap4SchmAtom.h" +#include "Ap4FrmaAtom.h" +#include "Ap4TimsAtom.h" +#include "Ap4RtpAtom.h" +#include "Ap4SdpAtom.h" +#include "Ap4IkmsAtom.h" +#include "Ap4IsfmAtom.h" +#include "Ap4IsltAtom.h" +#include "Ap4TrefTypeAtom.h" +#include "Ap4OmaDcf.h" +#include "Ap4IsmaCryp.h" +#include "Ap4OdafAtom.h" +#include "Ap4OhdrAtom.h" +#include "Ap4OdheAtom.h" +#include "Ap4OddaAtom.h" +#include "Ap4AvccAtom.h" +#include "Ap4Marlin.h" +#include "Ap4GrpiAtom.h" +#include "Ap48bdlAtom.h" +#include "Ap4MovieFragment.h" +#include "Ap4LinearReader.h" +#include "Ap4TfhdAtom.h" +#include "Ap4SampleSource.h" +#include "Ap4Mpeg2Ts.h" +#include "Ap4Piff.h" + +#endif // _AP4_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap48bdlAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap48bdlAtom.cpp new file mode 100644 index 000000000..99828d98b --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap48bdlAtom.cpp @@ -0,0 +1,127 @@ +/***************************************************************** +| +| AP4 - 8bdl Atoms +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap48bdlAtom.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_8bdlAtom) + +/*---------------------------------------------------------------------- +| AP4_8bdlAtom::AP4_8bdlAtom ++---------------------------------------------------------------------*/ +AP4_8bdlAtom::AP4_8bdlAtom(AP4_UI32 encoding, + AP4_UI32 encoding_version, + const AP4_Byte* data, + AP4_Size data_size) : + AP4_Atom(AP4_ATOM_TYPE_8BDL, (AP4_UI32)(AP4_ATOM_HEADER_SIZE+8+data_size)), + m_Encoding(encoding), + m_EncodingVersion(encoding_version), + m_BundleData(data, data_size) +{ +} + +/*---------------------------------------------------------------------- +| AP4_8bdlAtom::Create ++---------------------------------------------------------------------*/ +AP4_8bdlAtom* +AP4_8bdlAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + // make sure we have enough data + if (size < AP4_ATOM_HEADER_SIZE+8) { + return NULL; + } else { + return new AP4_8bdlAtom(size, stream); + } +} + +/*---------------------------------------------------------------------- +| AP4_8bdlAtom::AP4_8bdlAtom ++---------------------------------------------------------------------*/ +AP4_8bdlAtom::AP4_8bdlAtom(AP4_Size size, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_8BDL, (AP4_UI32)(size)), + m_BundleData(size-AP4_ATOM_HEADER_SIZE-8) +{ + stream.ReadUI32(m_Encoding); + stream.ReadUI32(m_EncodingVersion); + m_BundleData.SetDataSize(m_BundleData.GetBufferSize()); + stream.Read(m_BundleData.UseData(), m_BundleData.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| AP4_8bdlAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_8bdlAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // encoding + result = stream.WriteUI32(m_Encoding); + if (AP4_FAILED(result)) return result; + + // encoding version + result = stream.WriteUI32(m_EncodingVersion); + if (AP4_FAILED(result)) return result; + + // bundle_data + result = stream.Write(m_BundleData.GetData(), m_BundleData.GetDataSize()); + if (AP4_FAILED(result)) return result; + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_8bdlAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_8bdlAtom::InspectFields(AP4_AtomInspector& inspector) +{ + char enc[5]; + AP4_FormatFourChars(enc, m_Encoding); + inspector.AddField("encoding", enc); + inspector.AddField("encoding_version", m_EncodingVersion); + if (m_Encoding == AP4_8BDL_XML_DATA_ENCODING) { + // we, in fact have an xml string + AP4_String xml((const char*)m_BundleData.GetData(), m_BundleData.GetDataSize()); + inspector.AddField("bundle_data", xml.GetChars()); + } else { + inspector.AddField("bundle_data", m_BundleData.GetData(), m_BundleData.GetDataSize()); + } + + return AP4_SUCCESS; +} + + + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap48bdlAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap48bdlAtom.h new file mode 100644 index 000000000..3c3cadd2e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap48bdlAtom.h @@ -0,0 +1,81 @@ +/***************************************************************** +| +| AP4 - 8bdl Atoms +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + + #ifndef _AP4_8BDL_ATOM_H_ + #define _AP4_8BDL_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4DataBuffer.h" +#include "Ap4Atom.h" +#include "Ap4DynamicCast.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_8BDL_XML_DATA_ENCODING = AP4_ATOM_TYPE('x','m','l',' '); + +/*---------------------------------------------------------------------- +| AP4_8bdlAtom ++---------------------------------------------------------------------*/ +class AP4_8bdlAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_8bdlAtom, AP4_Atom) + + // virtual constructor + static AP4_8bdlAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // constructors + AP4_8bdlAtom(AP4_UI32 encoding, + AP4_UI32 encoding_version, + const AP4_Byte* data, + AP4_Size data_size); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetEncoding() { return m_Encoding; } + AP4_UI32 GetEncodingVersion() { return m_EncodingVersion; } + const AP4_DataBuffer& GetBundleData() { return m_BundleData; } + +private: + // methods + AP4_8bdlAtom(AP4_Size size, + AP4_ByteStream& stream); + + // members + AP4_UI32 m_Encoding; + AP4_UI32 m_EncodingVersion; + AP4_DataBuffer m_BundleData; +}; + +#endif // _AP4_8BDL_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Array.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Array.h new file mode 100644 index 000000000..b62bac22c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Array.h @@ -0,0 +1,233 @@ +/*****************************************************************
+|
+| AP4 - Arrays
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+/**
+ * @file
+ * @brief Arrays
+ */
+
+#ifndef _AP4_ARRAY_H_
+#define _AP4_ARRAY_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Config.h"
+#if defined(APT_CONFIG_HAVE_NEW_H)
+#include <new>
+#endif
+#include "Ap4Types.h"
+#include "Ap4Results.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const int AP4_ARRAY_INITIAL_COUNT = 64;
+
+/*----------------------------------------------------------------------
+| AP4_Array
++---------------------------------------------------------------------*/
+template <typename T>
+class AP4_Array
+{
+public:
+ // methods
+ AP4_Array(): m_AllocatedCount(0), m_ItemCount(0), m_Items(0) {}
+ AP4_Array(const T* items, AP4_Size count);
+ virtual ~AP4_Array();
+ AP4_Cardinal ItemCount() const { return m_ItemCount; }
+ AP4_Result Append(const T& item);
+ AP4_Result RemoveLast();
+ T& operator[](unsigned long idx) { return m_Items[idx]; }
+ const T& operator[](unsigned long idx) const { return m_Items[idx]; }
+ AP4_Result Clear();
+ AP4_Result EnsureCapacity(AP4_Cardinal count);
+ AP4_Result SetItemCount(AP4_Cardinal item_count);
+
+protected:
+ // members
+ AP4_Cardinal m_AllocatedCount;
+ AP4_Cardinal m_ItemCount;
+ T* m_Items;
+};
+
+/*----------------------------------------------------------------------
+| AP4_Array<T>::AP4_Array<T>
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Array<T>::AP4_Array(const T* items, AP4_Size count) :
+ m_AllocatedCount(count),
+ m_ItemCount(count),
+ m_Items((T*)::operator new(count*sizeof(T)))
+{
+ for (unsigned int i=0; i<count; i++) {
+ new ((void*)&m_Items[i]) T(items[i]);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_Array<T>::~AP4_Array<T>
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Array<T>::~AP4_Array()
+{
+ Clear();
+ ::operator delete((void*)m_Items);
+}
+
+/*----------------------------------------------------------------------
+| NPT_Array<T>::Clear
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_Array<T>::Clear()
+{
+ // destroy all items
+ for (AP4_Ordinal i=0; i<m_ItemCount; i++) {
+ m_Items[i].~T();
+ }
+
+ m_ItemCount = 0;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Array<T>::EnsureCapacity
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_Array<T>::EnsureCapacity(AP4_Cardinal count)
+{
+ // check if we already have enough
+ if (count <= m_AllocatedCount) return AP4_SUCCESS;
+
+ // (re)allocate the items
+ T* new_items = (T*) ::operator new (count*sizeof(T));
+ if (new_items == NULL) {
+ return AP4_ERROR_OUT_OF_MEMORY;
+ }
+ if (m_ItemCount && m_Items) {
+ for (unsigned int i=0; i<m_ItemCount; i++) {
+ new ((void*)&new_items[i]) T(m_Items[i]);
+ m_Items[i].~T();
+ }
+ ::operator delete((void*)m_Items);
+ }
+ m_Items = new_items;
+ m_AllocatedCount = count;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Array<T>::SetItemCount
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_Array<T>::SetItemCount(AP4_Cardinal item_count)
+{
+ // shortcut
+ if (item_count == m_ItemCount) return AP4_SUCCESS;
+
+ // check for a reduction in the number of items
+ if (item_count < m_ItemCount) {
+ // destruct the items that are no longer needed
+ for (unsigned int i=item_count; i<m_ItemCount; i++) {
+ m_Items[i].~T();
+ }
+ m_ItemCount = item_count;
+ return AP4_SUCCESS;
+ }
+
+ // grow the list
+ AP4_Result result = EnsureCapacity(item_count);
+ if (AP4_FAILED(result)) return result;
+
+ // construct the new items
+ for (unsigned int i=m_ItemCount; i<item_count; i++) {
+ new ((void*)&m_Items[i]) T();
+ }
+ m_ItemCount = item_count;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Array<T>::RemoveLast
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_Array<T>::RemoveLast()
+{
+ if (m_ItemCount) {
+ m_Items[--m_ItemCount].~T();
+ return AP4_SUCCESS;
+ } else {
+ return AP4_ERROR_OUT_OF_RANGE;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_Array<T>::Append
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_Array<T>::Append(const T& item)
+{
+ // ensure that we have enough space
+ if (m_AllocatedCount < m_ItemCount+1) {
+ // try double the size, with a minimum
+ unsigned long new_count = m_AllocatedCount?2*m_AllocatedCount:AP4_ARRAY_INITIAL_COUNT;
+
+ // if that's still not enough, just ask for what we need
+ if (new_count < m_ItemCount+1) new_count = m_ItemCount+1;
+
+ // reserve the space
+ AP4_Result result = EnsureCapacity(new_count);
+ if (result != AP4_SUCCESS) return result;
+ }
+
+ // store the item
+ new ((void*)&m_Items[m_ItemCount++]) T(item);
+
+ return AP4_SUCCESS;
+}
+
+#endif // _AP4_ARRAY_H_
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Atom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Atom.cpp new file mode 100644 index 000000000..a9bd81e6b --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Atom.cpp @@ -0,0 +1,899 @@ +/***************************************************************** +| +| AP4 - Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Utils.h" +#include "Ap4ContainerAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Debug.h" +#include "Ap4UuidAtom.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +static const unsigned int AP4_ATOM_MAX_CLONE_SIZE = 1048576; // 1 meg +static const unsigned int AP4_UNKNOWN_ATOM_MAX_LOCAL_PAYLOAD_SIZE = 4096; + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Atom) +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_AtomParent) +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_NullTerminatedStringAtom) + +/*---------------------------------------------------------------------- +| AP4_Atom::TypeFromString ++---------------------------------------------------------------------*/ +AP4_Atom::Type +AP4_Atom::TypeFromString(const char* s) +{ + // convert the name into an atom type + return ((AP4_UI32)s[0])<<24 | + ((AP4_UI32)s[1])<<16 | + ((AP4_UI32)s[2])<< 8 | + ((AP4_UI32)s[3]); +} + +/*---------------------------------------------------------------------- +| AP4_Atom::AP4_Atom ++---------------------------------------------------------------------*/ +AP4_Atom::AP4_Atom(Type type, AP4_UI32 size /* = AP4_ATOM_HEADER_SIZE */) : + m_Type(type), + m_Size32(size), + m_Size64(0), + m_IsFull(false), + m_Version(0), + m_Flags(0), + m_Parent(NULL) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Atom::AP4_Atom ++---------------------------------------------------------------------*/ +AP4_Atom::AP4_Atom(Type type, AP4_UI64 size, bool force_64) : + m_Type(type), + m_Size32(0), + m_Size64(0), + m_IsFull(false), + m_Version(0), + m_Flags(0), + m_Parent(NULL) +{ + SetSize(size, force_64); +} + +/*---------------------------------------------------------------------- +| AP4_Atom::AP4_Atom ++---------------------------------------------------------------------*/ +AP4_Atom::AP4_Atom(Type type, + AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags) : + m_Type(type), + m_Size32(size), + m_Size64(0), + m_IsFull(true), + m_Version(version), + m_Flags(flags), + m_Parent(NULL) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Atom::AP4_Atom ++---------------------------------------------------------------------*/ +AP4_Atom::AP4_Atom(Type type, + AP4_UI64 size, + bool force_64, + AP4_UI32 version, + AP4_UI32 flags) : + m_Type(type), + m_Size32(0), + m_Size64(0), + m_IsFull(true), + m_Version(version), + m_Flags(flags), + m_Parent(NULL) +{ + SetSize(size, force_64); +} + +/*---------------------------------------------------------------------- +| AP4_Atom::ReadFullHeader ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Atom::ReadFullHeader(AP4_ByteStream& stream, + AP4_UI32& version, + AP4_UI32& flags) +{ + AP4_UI32 header; + AP4_CHECK(stream.ReadUI32(header)); + version = (header>>24)&0x000000FF; + flags = (header )&0x00FFFFFF; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Atom::SetSize ++---------------------------------------------------------------------*/ +void +AP4_Atom::SetSize(AP4_UI64 size, bool force_64) +{ + if (!force_64) { + // see if we need to implicitely force 64-bit encoding + if (m_Size32 == 1 && m_Size64 <= 0xFFFFFFFF) { + // we have a forced 64-bit encoding + force_64 = true; + } + } + if ((size >> 32) == 0 && !force_64) { + m_Size32 = (AP4_UI32)size; + m_Size64 = 0; + } else { + m_Size32 = 1; + m_Size64 = size; + } +} + +/*---------------------------------------------------------------------- +| AP4_Atom::GetHeaderSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_Atom::GetHeaderSize() const +{ + return (m_IsFull ? AP4_FULL_ATOM_HEADER_SIZE : AP4_ATOM_HEADER_SIZE)+(m_Size32==1?8:0); +} + +/*---------------------------------------------------------------------- +| AP4_Atom::WriteHeader ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Atom::WriteHeader(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the size + result = stream.WriteUI32(m_Size32); + if (AP4_FAILED(result)) return result; + + // write the type + result = stream.WriteUI32(m_Type); + if (AP4_FAILED(result)) return result; + + // handle 64-bit sizes + if (m_Size32 == 1) { + result = stream.WriteUI64(m_Size64); + if (AP4_FAILED(result)) return result; + } + + // for full atoms, write version and flags + if (m_IsFull) { + result = stream.WriteUI08(m_Version); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI24(m_Flags); + if (AP4_FAILED(result)) return result; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Atom::Write ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Atom::Write(AP4_ByteStream& stream) +{ + AP4_Result result; + +#if defined(AP4_DEBUG) + AP4_Position before; + stream.Tell(before); +#endif + + // write the header + result = WriteHeader(stream); + if (AP4_FAILED(result)) return result; + + // write the fields + result = WriteFields(stream); + if (AP4_FAILED(result)) return result; + +#if defined(AP4_DEBUG) + AP4_Position after; + stream.Tell(after); + AP4_UI64 atom_size = GetSize(); + if (after-before != atom_size) { + AP4_Debug("ERROR: atom size mismatch (declared size=%d, actual size=%d)\n", + (AP4_UI32)atom_size, (AP4_UI32)(after-before)); + AP4_Atom* atom = this; + while (atom) { + char name[7]; + name[0] = '['; + AP4_FormatFourCharsPrintable(&name[1], atom->GetType()); + name[5] = ']'; + name[6] = '\0'; + AP4_Debug(" while writing %s\n", name); + atom = AP4_DYNAMIC_CAST(AP4_Atom, atom->GetParent()); + } + AP4_ASSERT(after-before == atom_size); + } +#endif + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Atom::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Atom::Inspect(AP4_AtomInspector& inspector) +{ + InspectHeader(inspector); + InspectFields(inspector); + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Atom::InspectHeader ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Atom::InspectHeader(AP4_AtomInspector& inspector) +{ + // write atom name + char name[7]; + name[0] = '['; + AP4_FormatFourCharsPrintable(&name[1], m_Type); + name[5] = ']'; + name[6] = '\0'; + char header[128]; + char extra[32] = ""; + if (m_IsFull) { + if (m_Version && m_Flags) { + AP4_FormatString(extra, sizeof(extra), + ", version=%d, flags=%x", + m_Version, + m_Flags); + } else if (m_Version) { + AP4_FormatString(extra, sizeof(extra), + ", version=%d", + m_Version); + } else if (m_Flags) { + AP4_FormatString(extra, sizeof(extra), + ", flags=%x", + m_Flags); + } + } + AP4_FormatString(header, sizeof(header), + "size=%ld+%lld%s", + GetHeaderSize(), + GetSize()-GetHeaderSize(), + extra); + inspector.StartElement(name, header); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Atom::Detach ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Atom::Detach() +{ + if (m_Parent) { + return m_Parent->RemoveChild(this); + } else { + return AP4_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| AP4_Atom::Clone ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_Atom::Clone() +{ + AP4_Atom* clone = NULL; + + // check the size (refuse to clone atoms that are too large) + AP4_LargeSize size = GetSize(); + if (size > AP4_ATOM_MAX_CLONE_SIZE) return NULL; + + // create a memory byte stream to which we can serialize + AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream((AP4_Size)GetSize()); + + // serialize to memory + if (AP4_FAILED(Write(*mbs))) goto end; + + // create the clone for the serialized form + mbs->Seek(0); + AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*mbs, clone); + +end: + // release the memory stream + mbs->Release(); + + return clone; +} + +/*---------------------------------------------------------------------- +| AP4_UnknownAtom::AP4_UnknownAtom ++---------------------------------------------------------------------*/ +AP4_UnknownAtom::AP4_UnknownAtom(Type type, + AP4_UI64 size, + AP4_ByteStream& stream) : + AP4_Atom(type, size), + m_SourceStream(&stream) +{ + if (size <= AP4_UNKNOWN_ATOM_MAX_LOCAL_PAYLOAD_SIZE && + type != AP4_ATOM_TYPE_MDAT) { + m_SourcePosition = 0; + m_SourceStream = NULL; + AP4_UI32 payload_size = (AP4_UI32)size-GetHeaderSize(); + m_Payload.SetDataSize(payload_size); + stream.Read(m_Payload.UseData(), payload_size); + return; + } + + // store source stream position + stream.Tell(m_SourcePosition); + + // clamp to the file size + AP4_UI64 file_size; + if (AP4_SUCCEEDED(stream.GetSize(file_size))) { + if (m_SourcePosition-GetHeaderSize()+size > file_size) { + if (m_Size32 == 1) { + // size is encoded as a large size + m_Size64 = file_size-m_SourcePosition; + } else { + AP4_ASSERT(size <= 0xFFFFFFFF); + m_Size32 = (AP4_UI32)(file_size-m_SourcePosition); + } + } + } + + // keep a reference to the source stream + m_SourceStream->AddReference(); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownAtom::AP4_UnknownAtom ++---------------------------------------------------------------------*/ +AP4_UnknownAtom::AP4_UnknownAtom(Type type, + const AP4_UI08* payload, + AP4_Size payload_size) : + AP4_Atom(type, AP4_ATOM_HEADER_SIZE+payload_size, false), + m_SourceStream(NULL), + m_SourcePosition(0) +{ + m_Payload.SetData(payload, payload_size); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownAtom::AP4_UnknownAtom ++---------------------------------------------------------------------*/ +AP4_UnknownAtom::AP4_UnknownAtom(const AP4_UnknownAtom& other) : + AP4_Atom(other.m_Type, (AP4_UI32)0), + m_SourceStream(other.m_SourceStream), + m_SourcePosition(other.m_SourcePosition), + m_Payload(other.m_Payload) +{ + m_Size32 = other.m_Size32; + m_Size64 = other.m_Size64; + if (m_SourceStream) { + m_SourceStream->AddReference(); + } +} + +/*---------------------------------------------------------------------- +| AP4_UnknownAtom::~AP4_UnknownAtom ++---------------------------------------------------------------------*/ +AP4_UnknownAtom::~AP4_UnknownAtom() +{ + // release the source stream reference + if (m_SourceStream) { + m_SourceStream->Release(); + } +} + +/*---------------------------------------------------------------------- +| AP4_UnknownAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_UnknownAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // if we don't have a source, write from the buffered payload + if (m_SourceStream == NULL) { + return stream.Write(m_Payload.GetData(), m_Payload.GetDataSize()); + } + + // remember the source position + AP4_Position position; + m_SourceStream->Tell(position); + + // seek into the source at the stored offset + result = m_SourceStream->Seek(m_SourcePosition); + if (AP4_FAILED(result)) return result; + + // copy the source stream to the output + AP4_UI64 payload_size = GetSize()-GetHeaderSize(); + result = m_SourceStream->CopyTo(stream, payload_size); + if (AP4_FAILED(result)) return result; + + // restore the original stream position + m_SourceStream->Seek(position); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_UnknownAtom::Clone ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_UnknownAtom::Clone() +{ + return new AP4_UnknownAtom(*this); +} + +/*---------------------------------------------------------------------- +| AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom ++---------------------------------------------------------------------*/ +AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom(AP4_Atom::Type type, const char* value) : + AP4_Atom(type, AP4_ATOM_HEADER_SIZE), + m_Value(value) +{ + m_Size32 += m_Value.GetLength()+1; +} + +/*---------------------------------------------------------------------- +| AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom ++---------------------------------------------------------------------*/ +AP4_NullTerminatedStringAtom::AP4_NullTerminatedStringAtom(AP4_Atom::Type type, + AP4_UI64 size, + AP4_ByteStream& stream) : + AP4_Atom(type, size) +{ + AP4_Size str_size = (AP4_Size)size-AP4_ATOM_HEADER_SIZE; + char* str = new char[str_size]; + stream.Read(str, str_size); + str[str_size-1] = '\0'; // force null-termination + m_Value = str; +} + +/*---------------------------------------------------------------------- +| AP4_NullTerminatedStringAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_NullTerminatedStringAtom::WriteFields(AP4_ByteStream& stream) +{ + if (m_Size32 > AP4_ATOM_HEADER_SIZE) { + AP4_Result result = stream.Write(m_Value.GetChars(), m_Value.GetLength()+1); + if (AP4_FAILED(result)) return result; + + // pad with zeros if necessary + AP4_Size padding = m_Size32-(AP4_ATOM_HEADER_SIZE+m_Value.GetLength()+1); + while (padding--) stream.WriteUI08(0); + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_NullTerminatedStringAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_NullTerminatedStringAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("string value", m_Value.GetChars()); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AtomParent::~AP4_AtomParent ++---------------------------------------------------------------------*/ +AP4_AtomParent::~AP4_AtomParent() +{ + m_Children.DeleteReferences(); +} + +/*---------------------------------------------------------------------- +| AP4_AtomParent::AddChild ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AtomParent::AddChild(AP4_Atom* child, int position) +{ + // check that the child does not already have a parent + if (child->GetParent() != NULL) return AP4_ERROR_INVALID_PARAMETERS; + + // attach the child + AP4_Result result; + if (position == -1) { + // insert at the tail + result = m_Children.Add(child); + } else if (position == 0) { + // insert at the head + result = m_Children.Insert(NULL, child); + } else { + // insert after <n-1> + AP4_List<AP4_Atom>::Item* insertion_point = m_Children.FirstItem(); + unsigned int count = position; + while (insertion_point && --count) { + insertion_point = insertion_point->GetNext(); + } + if (insertion_point) { + result = m_Children.Insert(insertion_point, child); + } else { + result = AP4_ERROR_OUT_OF_RANGE; + } + } + if (AP4_FAILED(result)) return result; + + // notify the child of its parent + child->SetParent(this); + + // get a chance to update + OnChildAdded(child); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AtomParent::RemoveChild ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AtomParent::RemoveChild(AP4_Atom* child) +{ + // check that this is our child + if (child->GetParent() != this) return AP4_ERROR_INVALID_PARAMETERS; + + // remove the child + AP4_Result result = m_Children.Remove(child); + if (AP4_FAILED(result)) return result; + + // notify that child that it is orphaned + child->SetParent(NULL); + + // get a chance to update + OnChildRemoved(child); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AtomParent::DeleteChild ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AtomParent::DeleteChild(AP4_Atom::Type type, AP4_Ordinal index /* = 0 */) +{ + // find the child + AP4_Atom* child = GetChild(type, index); + if (child == NULL) return AP4_FAILURE; + + // remove the child + AP4_Result result = RemoveChild(child); + if (AP4_FAILED(result)) return result; + + // delete the child + delete child; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AtomParent::GetChild ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_AtomParent::GetChild(AP4_Atom::Type type, AP4_Ordinal index /* = 0 */) const +{ + AP4_Atom* atom; + AP4_Result result = m_Children.Find(AP4_AtomFinder(type, index), atom); + if (AP4_SUCCEEDED(result)) { + return atom; + } else { + return NULL; + } +} + +/*---------------------------------------------------------------------- +| AP4_AtomParent::GetChild ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_AtomParent::GetChild(const AP4_UI08* uuid, AP4_Ordinal index /* = 0 */) const +{ + for (AP4_List<AP4_Atom>::Item* item = m_Children.FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* atom = item->GetData(); + if (atom->GetType() == AP4_ATOM_TYPE_UUID) { + AP4_UuidAtom* uuid_atom = AP4_DYNAMIC_CAST(AP4_UuidAtom, atom); + if (AP4_CompareMemory(uuid_atom->GetUuid(), uuid, 16) == 0) { + if (index == 0) return atom; + --index; + } + } + } + return NULL; +} + +/*---------------------------------------------------------------------- +| AP4_AtomParent::FindChild ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_AtomParent::FindChild(const char* path, + bool auto_create, + bool auto_create_full) +{ + // start from here + AP4_AtomParent* parent = this; + + // walk the path + while (path[0] && path[1] && path[2] && path[3]) { + // we have 4 valid chars + const char* tail; + int index = 0; + if (path[4] == '\0') { + tail = NULL; + } else if (path[4] == '/') { + // separator + tail = &path[5]; + } else if (path[4] == '[') { + const char* x = &path[5]; + while (*x >= '0' && *x <= '9') { + index = 10*index+(*x++ - '0'); + } + if (x[0] == ']') { + if (x[1] == '\0') { + tail = NULL; + } else { + tail = x+2; + } + } else { + // malformed path + return NULL; + } + } else { + // malformed path + return NULL; + } + + // look for this atom in the current list + AP4_Atom::Type type = AP4_ATOM_TYPE(path[0], path[1], path[2], path[3]); + AP4_Atom* atom = parent->GetChild(type, index); + if (atom == NULL) { + // not found + if (auto_create && (index == 0)) { + if (auto_create_full) { + atom = new AP4_ContainerAtom(type, (AP4_UI32)0, (AP4_UI32)0); + } else { + atom = new AP4_ContainerAtom(type); + } + parent->AddChild(atom); + } else { + return NULL; + } + } + + if (tail) { + path = tail; + // if this atom is an atom parent, recurse + parent = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom); + if (parent == NULL) return NULL; + } else { + return atom; + } + } + + // not found + return NULL; +} + +/*---------------------------------------------------------------------- +| AP4_AtomListWriter::Action ++---------------------------------------------------------------------*/ +const unsigned int AP4_ATOM_LIST_WRITER_MAX_PADDING=1024; + +AP4_Result +AP4_AtomListWriter::Action(AP4_Atom* atom) const +{ + AP4_Position before; + m_Stream.Tell(before); + + atom->Write(m_Stream); + + AP4_Position after; + m_Stream.Tell(after); + + AP4_UI64 bytes_written = after-before; + AP4_ASSERT(bytes_written <= atom->GetSize()); + if (bytes_written < atom->GetSize()) { + AP4_Debug("WARNING: atom serialized to fewer bytes than declared size\n"); + AP4_UI64 padding = atom->GetSize()-bytes_written; + if (padding > AP4_ATOM_LIST_WRITER_MAX_PADDING) { + AP4_Debug("WARNING: padding would be too large\n"); + return AP4_FAILURE; + } else { + for (unsigned int i=0; i<padding; i++) { + m_Stream.WriteUI08(0); + } + } + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_MakePrefixString ++---------------------------------------------------------------------*/ +static void +AP4_MakePrefixString(unsigned int indent, char* prefix, AP4_Size size) +{ + if (size == 0) return; + if (indent >= size-1) indent = size-1; + for (unsigned int i=0; i<indent; i++) { + prefix[i] = ' '; + } + prefix[indent] = '\0'; +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::AP4_PrintInspector ++---------------------------------------------------------------------*/ + AP4_PrintInspector::AP4_PrintInspector(AP4_ByteStream& stream, AP4_Cardinal indent) : + m_Stream(&stream), + m_Indent(indent) +{ + m_Stream->AddReference(); +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::~AP4_PrintInspector ++---------------------------------------------------------------------*/ +AP4_PrintInspector::~AP4_PrintInspector() +{ + m_Stream->Release(); +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::StartElement ++---------------------------------------------------------------------*/ +void +AP4_PrintInspector::StartElement(const char* name, const char* info) +{ + char prefix[256]; + AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix)); + m_Stream->WriteString(prefix); + m_Stream->WriteString(name); + if (info) { + m_Stream->Write(" ", 1); + m_Stream->WriteString(info); + } + m_Stream->Write("\n", 1); + + m_Indent += 2; +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::EndElement ++---------------------------------------------------------------------*/ +void +AP4_PrintInspector::EndElement() +{ + m_Indent -= 2; +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::AddField ++---------------------------------------------------------------------*/ +void +AP4_PrintInspector::AddField(const char* name, const char* value, FormatHint) +{ + char prefix[256]; + AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix)); + m_Stream->WriteString(prefix); + + m_Stream->WriteString(name); + m_Stream->WriteString(" = "); + m_Stream->WriteString(value); + m_Stream->Write("\n", 1); +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::AddField ++---------------------------------------------------------------------*/ +void +AP4_PrintInspector::AddField(const char* name, AP4_UI64 value, FormatHint hint) +{ + char prefix[256]; + AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix)); + m_Stream->WriteString(prefix); + + char str[32]; + AP4_FormatString(str, sizeof(str), + hint == HINT_HEX ? "%llx":"%lld", + value); + m_Stream->WriteString(name); + m_Stream->WriteString(" = "); + m_Stream->WriteString(str); + m_Stream->Write("\n", 1); +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::AddFieldF ++---------------------------------------------------------------------*/ +void +AP4_PrintInspector::AddFieldF(const char* name, float value, FormatHint /*hint*/) +{ + char prefix[256]; + AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix)); + m_Stream->WriteString(prefix); + + char str[32]; + AP4_FormatString(str, sizeof(str), + "%f", + value); + m_Stream->WriteString(name); + m_Stream->WriteString(" = "); + m_Stream->WriteString(str); + m_Stream->Write("\n", 1); +} + +/*---------------------------------------------------------------------- +| AP4_PrintInspector::AddField ++---------------------------------------------------------------------*/ +void +AP4_PrintInspector::AddField(const char* name, + const unsigned char* bytes, + AP4_Size byte_count, + FormatHint /* hint */) +{ + char prefix[256]; + AP4_MakePrefixString(m_Indent, prefix, sizeof(prefix)); + m_Stream->WriteString(prefix); + + m_Stream->WriteString(name); + m_Stream->WriteString(" = ["); + unsigned int offset = 1; + char byte[4]; + for (unsigned int i=0; i<byte_count; i++) { + AP4_FormatString(byte, 4, " %02x", bytes[i]); + m_Stream->Write(&byte[offset], 3-offset); + offset = 0; + } + m_Stream->Write("]\n", 2); +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Atom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Atom.h new file mode 100644 index 000000000..7301821a3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Atom.h @@ -0,0 +1,542 @@ +/***************************************************************** +| +| AP4 - Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ +/** +* @file +* @brief Atoms +*/ + +#ifndef _AP4_ATOM_H_ +#define _AP4_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4ByteStream.h" +#include "Ap4String.h" +#include "Ap4Debug.h" +#include "Ap4DynamicCast.h" + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define AP4_ATOM_TYPE(c1,c2,c3,c4) \ + ((((AP4_UI32)c1)<<24) | \ + (((AP4_UI32)c2)<<16) | \ + (((AP4_UI32)c3)<< 8) | \ + (((AP4_UI32)c4) )) + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_ATOM_HEADER_SIZE = 8; +const AP4_UI32 AP4_ATOM_HEADER_SIZE_64 = 16; +const AP4_UI32 AP4_FULL_ATOM_HEADER_SIZE = 12; +const AP4_UI32 AP4_FULL_ATOM_HEADER_SIZE_64 = 20; +const AP4_UI32 AP4_ATOM_MAX_NAME_SIZE = 256; +const AP4_UI32 AP4_ATOM_MAX_URI_SIZE = 512; + +/*---------------------------------------------------------------------- +| forward references ++---------------------------------------------------------------------*/ +class AP4_AtomParent; + +/*---------------------------------------------------------------------- +| AP4_AtomInspector ++---------------------------------------------------------------------*/ +/** + * Class used in a visitor pattern to walk all the atoms in a tree of + * #AP4_Atom objects. + */ +class AP4_AtomInspector { +public: + // types + typedef enum { + HINT_NONE = 0, + HINT_HEX = 1, + HINT_BOOLEAN = 2 + } FormatHint; + + // constructor and destructor + AP4_AtomInspector() {} + virtual ~AP4_AtomInspector() {} + + // methods + void SetVerbosity(AP4_Ordinal verbosity) { m_Verbosity = verbosity; } + AP4_Ordinal GetVerbosity() { return m_Verbosity; } + + // virtual methods + virtual void StartElement(const char* /* name */, + const char* /* extra = NULL */) {} + virtual void EndElement() {} + virtual void AddField(const char* /* name */, + AP4_UI64 /* value */, + FormatHint hint = HINT_NONE) { + (void)hint; // gcc warning + } + virtual void AddFieldF(const char* /* name */, + float /* value */, + FormatHint hint = HINT_NONE) { + (void)hint; // gcc warning + } + virtual void AddField(const char* /* name */, + const char* /* value */, + FormatHint hint = HINT_NONE) { + (void)hint; // gcc warning + } + virtual void AddField(const char* /* name */, + const unsigned char* /* bytes */, + AP4_Size /* byte_count */, + FormatHint hint = HINT_NONE) { + (void)hint; // gcc warning + } + +protected: + AP4_Ordinal m_Verbosity; +}; + +/*---------------------------------------------------------------------- +| AP4_PrintInspector ++---------------------------------------------------------------------*/ +class AP4_PrintInspector : public AP4_AtomInspector { +public: + AP4_PrintInspector(AP4_ByteStream& stream, AP4_Cardinal indent=0); + ~AP4_PrintInspector(); + + // methods + void StartElement(const char* name, const char* info); + void EndElement(); + void AddField(const char* name, AP4_UI64 value, FormatHint hint); + void AddFieldF(const char* name, float value, FormatHint hint); + void AddField(const char* name, const char* value, FormatHint hint); + void AddField(const char* name, const unsigned char* bytes, AP4_Size size, FormatHint hint); + +private: + // members + AP4_ByteStream* m_Stream; + AP4_Cardinal m_Indent; +}; + +/*---------------------------------------------------------------------- +| AP4_Atom ++---------------------------------------------------------------------*/ +/** + * Abstract base class for all atom types. + */ +class AP4_Atom { +public: + AP4_IMPLEMENT_DYNAMIC_CAST(AP4_Atom) + + // types + typedef AP4_UI32 Type; + + // class methods + static Type TypeFromString(const char* four_cc); + static AP4_Result ReadFullHeader(AP4_ByteStream& stream, + AP4_UI32& version, + AP4_UI32& flags); + + // constructors + /** + * Create a simple atom with a specified type and 32-bit size. + */ + explicit AP4_Atom(Type type, AP4_UI32 size = AP4_ATOM_HEADER_SIZE); + + /** + * Create a simple atom with a specified type and 64-bit size. + */ + explicit AP4_Atom(Type type, AP4_UI64 size, bool force_64=false); + + /** + * Create a full atom with a specified type, 32-bit size, version and flags. + */ + explicit AP4_Atom(Type type, + AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags); + + /** + * Create a full atom with a specified type, 64-bit size, version and flags. + */ + explicit AP4_Atom(Type type, + AP4_UI64 size, + bool force_64, + AP4_UI32 version, + AP4_UI32 flags); + + // destructor + virtual ~AP4_Atom() {} + + // methods + AP4_UI32 GetFlags() const { return m_Flags; } + void SetFlags(AP4_UI32 flags) { m_Flags = flags; } + Type GetType() const { return m_Type; } + void SetType(Type type) { m_Type = type; } + virtual AP4_Size GetHeaderSize() const; + AP4_UI64 GetSize() const { return m_Size32 == 1?m_Size64:m_Size32; } + void SetSize(AP4_UI64 size, bool force_64 = false); + AP4_UI32 GetSize32() const { return m_Size32; } + void SetSize32(AP4_UI32 size) { m_Size32 = size; } + AP4_UI64 GetSize64() const { return m_Size64; } + void SetSize64(AP4_UI64 size) { m_Size64 = size; } + virtual AP4_Result Write(AP4_ByteStream& stream); + virtual AP4_Result WriteHeader(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream) = 0; + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + virtual AP4_Result InspectHeader(AP4_AtomInspector& inspector); + virtual AP4_Result InspectFields(AP4_AtomInspector& /* inspector */) { + return AP4_SUCCESS; + } + + // parent/child relationship methods + virtual AP4_Result SetParent(AP4_AtomParent* parent) { + m_Parent = parent; + return AP4_SUCCESS; + } + virtual AP4_AtomParent* GetParent() { return m_Parent; } + virtual AP4_Result Detach(); + + /** + * Create a clone of the object. + * This method returns a clone of the atom, or NULL if + * the atom cannot be cloned. + * Override this if your want to make an atom cloneable in a more + * efficient way than the default implementation. + */ + virtual AP4_Atom* Clone(); + + protected: + // members + Type m_Type; + AP4_UI32 m_Size32; + AP4_UI64 m_Size64; // this is 0 if m_Size is not 1 (encoded in 32-bits) + // and non-zero only if m_Size is 1 (encoded in 64-bits) + bool m_IsFull; + AP4_UI32 m_Version; + AP4_UI32 m_Flags; + AP4_AtomParent* m_Parent; +}; + +/*---------------------------------------------------------------------- +| AP4_AtomParent ++---------------------------------------------------------------------*/ +/** + * Base class for containers of atoms. + * This class also implements the logic for finding descendents by name. + */ +class AP4_AtomParent { +public: + AP4_IMPLEMENT_DYNAMIC_CAST(AP4_AtomParent) + + // base methods + virtual ~AP4_AtomParent(); + AP4_List<AP4_Atom>& GetChildren() { return m_Children; } + virtual AP4_Result AddChild(AP4_Atom* child, int position = -1); + virtual AP4_Result RemoveChild(AP4_Atom* child); + virtual AP4_Result DeleteChild(AP4_Atom::Type type, AP4_Ordinal index = 0); + virtual AP4_Atom* GetChild(AP4_Atom::Type type, AP4_Ordinal index = 0) const; + virtual AP4_Atom* GetChild(const AP4_UI08* uuid, AP4_Ordinal index = 0) const; + virtual AP4_Atom* FindChild(const char* path, + bool auto_create = false, + bool auto_create_full = false); + + // methods designed to be overridden + virtual void OnChildChanged(AP4_Atom* /* child */) {} + virtual void OnChildAdded(AP4_Atom* /* child */) {} + virtual void OnChildRemoved(AP4_Atom* /* child */) {} + +protected: + // members + AP4_List<AP4_Atom> m_Children; +}; + +/*---------------------------------------------------------------------- +| AP4_UnknownAtom ++---------------------------------------------------------------------*/ +/** + * Class that represents atoms for which there is no specific support. + * Instances of this class keep a reference to the stream from which + * the atom is parsed, so that it can read the atom's payload when it + * is serialized. + * If the atom is small, its payload is actually read and stored in + * a data buffer, so no reference to the source stream is kept + */ +class AP4_UnknownAtom : public AP4_Atom { +public: + // constructor and destructor + AP4_UnknownAtom(AP4_Atom::Type type, + AP4_UI64 size, + AP4_ByteStream& stream); + AP4_UnknownAtom(AP4_Atom::Type type, const AP4_UI08* payload, AP4_Size payload_size); + AP4_UnknownAtom(const AP4_UnknownAtom& other); + ~AP4_UnknownAtom(); + + // methods + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Atom* Clone(); + +private: + // members + AP4_ByteStream* m_SourceStream; + AP4_Position m_SourcePosition; + AP4_DataBuffer m_Payload; +}; + +/*---------------------------------------------------------------------- +| AP4_NullTerminatedStringAtom ++---------------------------------------------------------------------*/ +/** + * Generic Class usd for all atoms that contain a single null-terminated + * string. + */ +class AP4_NullTerminatedStringAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_NullTerminatedStringAtom, AP4_Atom) + + // constructors + AP4_NullTerminatedStringAtom(AP4_Atom::Type type, AP4_UI64 size, AP4_ByteStream& stream); + AP4_NullTerminatedStringAtom(AP4_Atom::Type type, const char* value); + + // accessors + const AP4_String& GetValue() { return m_Value; } + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // members + AP4_String m_Value; +}; + +/*---------------------------------------------------------------------- +| atom types ++---------------------------------------------------------------------*/ +const AP4_Atom::Type AP4_ATOM_TYPE_UDTA = AP4_ATOM_TYPE('u','d','t','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_URL = AP4_ATOM_TYPE('u','r','l',' '); +const AP4_Atom::Type AP4_ATOM_TYPE_TRAK = AP4_ATOM_TYPE('t','r','a','k'); +const AP4_Atom::Type AP4_ATOM_TYPE_TRAF = AP4_ATOM_TYPE('t','r','a','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_TKHD = AP4_ATOM_TYPE('t','k','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_TFHD = AP4_ATOM_TYPE('t','f','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_TRUN = AP4_ATOM_TYPE('t','r','u','n'); +const AP4_Atom::Type AP4_ATOM_TYPE_STTS = AP4_ATOM_TYPE('s','t','t','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_STSZ = AP4_ATOM_TYPE('s','t','s','z'); +const AP4_Atom::Type AP4_ATOM_TYPE_STSS = AP4_ATOM_TYPE('s','t','s','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_STSD = AP4_ATOM_TYPE('s','t','s','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_STSC = AP4_ATOM_TYPE('s','t','s','c'); +const AP4_Atom::Type AP4_ATOM_TYPE_STCO = AP4_ATOM_TYPE('s','t','c','o'); +const AP4_Atom::Type AP4_ATOM_TYPE_CO64 = AP4_ATOM_TYPE('c','o','6','4'); +const AP4_Atom::Type AP4_ATOM_TYPE_STBL = AP4_ATOM_TYPE('s','t','b','l'); +const AP4_Atom::Type AP4_ATOM_TYPE_SINF = AP4_ATOM_TYPE('s','i','n','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_SCHM = AP4_ATOM_TYPE('s','c','h','m'); +const AP4_Atom::Type AP4_ATOM_TYPE_SCHI = AP4_ATOM_TYPE('s','c','h','i'); +const AP4_Atom::Type AP4_ATOM_TYPE_MVHD = AP4_ATOM_TYPE('m','v','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_MEHD = AP4_ATOM_TYPE('m','e','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_MP4S = AP4_ATOM_TYPE('m','p','4','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_MP4A = AP4_ATOM_TYPE('m','p','4','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_MP4V = AP4_ATOM_TYPE('m','p','4','v'); +const AP4_Atom::Type AP4_ATOM_TYPE_AVC1 = AP4_ATOM_TYPE('a','v','c','1'); +const AP4_Atom::Type AP4_ATOM_TYPE_ALAC = AP4_ATOM_TYPE('a','l','a','c'); +const AP4_Atom::Type AP4_ATOM_TYPE_ENCA = AP4_ATOM_TYPE('e','n','c','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_ENCV = AP4_ATOM_TYPE('e','n','c','v'); +const AP4_Atom::Type AP4_ATOM_TYPE_MOOV = AP4_ATOM_TYPE('m','o','o','v'); +const AP4_Atom::Type AP4_ATOM_TYPE_MOOF = AP4_ATOM_TYPE('m','o','o','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_MVEX = AP4_ATOM_TYPE('m','v','e','x'); +const AP4_Atom::Type AP4_ATOM_TYPE_TREX = AP4_ATOM_TYPE('t','r','e','x'); +const AP4_Atom::Type AP4_ATOM_TYPE_MINF = AP4_ATOM_TYPE('m','i','n','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_META = AP4_ATOM_TYPE('m','e','t','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_MDHD = AP4_ATOM_TYPE('m','d','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_MFHD = AP4_ATOM_TYPE('m','f','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_ILST = AP4_ATOM_TYPE('i','l','s','t'); +const AP4_Atom::Type AP4_ATOM_TYPE_HDLR = AP4_ATOM_TYPE('h','d','l','r'); +const AP4_Atom::Type AP4_ATOM_TYPE_FTYP = AP4_ATOM_TYPE('f','t','y','p'); +const AP4_Atom::Type AP4_ATOM_TYPE_IODS = AP4_ATOM_TYPE('i','o','d','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_ESDS = AP4_ATOM_TYPE('e','s','d','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_EDTS = AP4_ATOM_TYPE('e','d','t','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_DRMS = AP4_ATOM_TYPE('d','r','m','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_DRMI = AP4_ATOM_TYPE('d','r','m','i'); +const AP4_Atom::Type AP4_ATOM_TYPE_DREF = AP4_ATOM_TYPE('d','r','e','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_DINF = AP4_ATOM_TYPE('d','i','n','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_CTTS = AP4_ATOM_TYPE('c','t','t','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_MDIA = AP4_ATOM_TYPE('m','d','i','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_ELST = AP4_ATOM_TYPE('e','l','s','t'); +const AP4_Atom::Type AP4_ATOM_TYPE_VMHD = AP4_ATOM_TYPE('v','m','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_SMHD = AP4_ATOM_TYPE('s','m','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_NMHD = AP4_ATOM_TYPE('n','m','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_HMHD = AP4_ATOM_TYPE('h','m','h','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_FRMA = AP4_ATOM_TYPE('f','r','m','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_MDAT = AP4_ATOM_TYPE('m','d','a','t'); +const AP4_Atom::Type AP4_ATOM_TYPE_FREE = AP4_ATOM_TYPE('f','r','e','e'); +const AP4_Atom::Type AP4_ATOM_TYPE_TIMS = AP4_ATOM_TYPE('t','i','m','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_RTP_ = AP4_ATOM_TYPE('r','t','p',' '); +const AP4_Atom::Type AP4_ATOM_TYPE_HNTI = AP4_ATOM_TYPE('h','n','t','i'); +const AP4_Atom::Type AP4_ATOM_TYPE_SDP_ = AP4_ATOM_TYPE('s','d','p',' '); +const AP4_Atom::Type AP4_ATOM_TYPE_IKMS = AP4_ATOM_TYPE('i','K','M','S'); +const AP4_Atom::Type AP4_ATOM_TYPE_ISFM = AP4_ATOM_TYPE('i','S','F','M'); +const AP4_Atom::Type AP4_ATOM_TYPE_ISLT = AP4_ATOM_TYPE('i','S','L','T'); +const AP4_Atom::Type AP4_ATOM_TYPE_TREF = AP4_ATOM_TYPE('t','r','e','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_HINT = AP4_ATOM_TYPE('h','i','n','t'); +const AP4_Atom::Type AP4_ATOM_TYPE_CDSC = AP4_ATOM_TYPE('c','d','s','c'); +const AP4_Atom::Type AP4_ATOM_TYPE_MPOD = AP4_ATOM_TYPE('m','p','o','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_IPIR = AP4_ATOM_TYPE('i','p','i','r'); +const AP4_Atom::Type AP4_ATOM_TYPE_CHAP = AP4_ATOM_TYPE('c','h','a','p'); +const AP4_Atom::Type AP4_ATOM_TYPE_ALIS = AP4_ATOM_TYPE('a','l','i','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_SYNC = AP4_ATOM_TYPE('s','y','n','c'); +const AP4_Atom::Type AP4_ATOM_TYPE_DPND = AP4_ATOM_TYPE('d','p','n','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_ODRM = AP4_ATOM_TYPE('o','d','r','m'); +const AP4_Atom::Type AP4_ATOM_TYPE_ODKM = AP4_ATOM_TYPE('o','d','k','m'); +const AP4_Atom::Type AP4_ATOM_TYPE_OHDR = AP4_ATOM_TYPE('o','h','d','r'); +const AP4_Atom::Type AP4_ATOM_TYPE_ODDA = AP4_ATOM_TYPE('o','d','d','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_ODHE = AP4_ATOM_TYPE('o','d','h','e'); +const AP4_Atom::Type AP4_ATOM_TYPE_ODAF = AP4_ATOM_TYPE('o','d','a','f'); +const AP4_Atom::Type AP4_ATOM_TYPE_GRPI = AP4_ATOM_TYPE('g','r','p','i'); +const AP4_Atom::Type AP4_ATOM_TYPE_IPRO = AP4_ATOM_TYPE('i','p','r','o'); +const AP4_Atom::Type AP4_ATOM_TYPE_MDRI = AP4_ATOM_TYPE('m','d','r','i'); +const AP4_Atom::Type AP4_ATOM_TYPE_AVCC = AP4_ATOM_TYPE('a','v','c','C'); +const AP4_Atom::Type AP4_ATOM_TYPE_WAVE = AP4_ATOM_TYPE('w','a','v','e'); +const AP4_Atom::Type AP4_ATOM_TYPE_WIDE = AP4_ATOM_TYPE('w','i','d','e'); +const AP4_Atom::Type AP4_ATOM_TYPE_UUID = AP4_ATOM_TYPE('u','u','i','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_8ID_ = AP4_ATOM_TYPE('8','i','d',' '); +const AP4_Atom::Type AP4_ATOM_TYPE_8BDL = AP4_ATOM_TYPE('8','b','d','l'); +const AP4_Atom::Type AP4_ATOM_TYPE_AC_3 = AP4_ATOM_TYPE('a','c','-','3'); +const AP4_Atom::Type AP4_ATOM_TYPE_EC_3 = AP4_ATOM_TYPE('e','c','-','3'); +const AP4_Atom::Type AP4_ATOM_TYPE_MFRA = AP4_ATOM_TYPE('m','f','r','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_TFRA = AP4_ATOM_TYPE('t','f','r','a'); +const AP4_Atom::Type AP4_ATOM_TYPE_MFRO = AP4_ATOM_TYPE('m','f','r','o'); + +// ==> Start patch MPC +const AP4_Atom::Type AP4_ATOM_TYPE_FTAB = AP4_ATOM_TYPE('f','t','a','b'); +const AP4_Atom::Type AP4_ATOM_TYPE_CHPL = AP4_ATOM_TYPE('c','h','p','l'); +const AP4_Atom::Type AP4_ATOM_TYPE_SAC3 = AP4_ATOM_TYPE('s','a','c','3'); +const AP4_Atom::Type AP4_ATOM_TYPE_DTSC = AP4_ATOM_TYPE('d','t','s','c'); +const AP4_Atom::Type AP4_ATOM_TYPE_NAM = AP4_ATOM_TYPE(169,'n','a','m'); + +const AP4_Atom::Type AP4_ATOM_TYPE_ART = AP4_ATOM_TYPE(169,'A','R','T'); +const AP4_Atom::Type AP4_ATOM_TYPE_WRT = AP4_ATOM_TYPE(169,'w','r','t'); +const AP4_Atom::Type AP4_ATOM_TYPE_ALB = AP4_ATOM_TYPE(169,'a','l','b'); +const AP4_Atom::Type AP4_ATOM_TYPE_DAY = AP4_ATOM_TYPE(169,'d','a','y'); +const AP4_Atom::Type AP4_ATOM_TYPE_TOO = AP4_ATOM_TYPE(169,'t','o','o'); +const AP4_Atom::Type AP4_ATOM_TYPE_CMT = AP4_ATOM_TYPE(169,'c','m','t'); +const AP4_Atom::Type AP4_ATOM_TYPE_GEN = AP4_ATOM_TYPE(169,'g','e','n'); + +const AP4_Atom::Type AP4_ATOM_TYPE_TEXT = AP4_ATOM_TYPE('t','e','x','t'); +const AP4_Atom::Type AP4_ATOM_TYPE_TX3G = AP4_ATOM_TYPE('t','x','3','g'); +const AP4_Atom::Type AP4_ATOM_TYPE_CVID = AP4_ATOM_TYPE('c','v','i','d'); +const AP4_Atom::Type AP4_ATOM_TYPE_SVQ1 = AP4_ATOM_TYPE('S','V','Q','1'); +const AP4_Atom::Type AP4_ATOM_TYPE_SVQ2 = AP4_ATOM_TYPE('S','V','Q','2'); +const AP4_Atom::Type AP4_ATOM_TYPE_SVQ3 = AP4_ATOM_TYPE('S','V','Q','3'); +const AP4_Atom::Type AP4_ATOM_TYPE_H263 = AP4_ATOM_TYPE('h','2','6','3'); +const AP4_Atom::Type AP4_ATOM_TYPE_S263 = AP4_ATOM_TYPE('s','2','6','3'); + +const AP4_Atom::Type AP4_ATOM_TYPE_SAMR = AP4_ATOM_TYPE('s','a','m','r'); +const AP4_Atom::Type AP4_ATOM_TYPE__MP3 = AP4_ATOM_TYPE('.','m','p','3'); +const AP4_Atom::Type AP4_ATOM_TYPE_IMA4 = AP4_ATOM_TYPE('i','m','a','4'); +const AP4_Atom::Type AP4_ATOM_TYPE_QDMC = AP4_ATOM_TYPE('Q','D','M','C'); +const AP4_Atom::Type AP4_ATOM_TYPE_QDM2 = AP4_ATOM_TYPE('Q','D','M','2'); +const AP4_Atom::Type AP4_ATOM_TYPE_TWOS = AP4_ATOM_TYPE('t','w','o','s'); +const AP4_Atom::Type AP4_ATOM_TYPE_SOWT = AP4_ATOM_TYPE('s','o','w','t'); +
+const AP4_Atom::Type AP4_ATOM_TYPE_CMOV = AP4_ATOM_TYPE('c','m','o','v');
+const AP4_Atom::Type AP4_ATOM_TYPE_DCOM = AP4_ATOM_TYPE('d','c','o','m');
+const AP4_Atom::Type AP4_ATOM_TYPE_CMVD = AP4_ATOM_TYPE('c','m','v','d');
+ +// <== End patch MPC + +/*---------------------------------------------------------------------- +| AP4_AtomListInspector ++---------------------------------------------------------------------*/ +class AP4_AtomListInspector : public AP4_List<AP4_Atom>::Item::Operator +{ + public: + AP4_AtomListInspector(AP4_AtomInspector& inspector) : + m_Inspector(inspector) {} + AP4_Result Action(AP4_Atom* atom) const { + atom->Inspect(m_Inspector); + return AP4_SUCCESS; + } + + private: + AP4_AtomInspector& m_Inspector; +}; + +/*---------------------------------------------------------------------- +| AP4_AtomListWriter ++---------------------------------------------------------------------*/ +class AP4_AtomListWriter : public AP4_List<AP4_Atom>::Item::Operator +{ + public: + AP4_AtomListWriter(AP4_ByteStream& stream) : + m_Stream(stream) {} + AP4_Result Action(AP4_Atom* atom) const; + + private: + AP4_ByteStream& m_Stream; +}; + +/*---------------------------------------------------------------------- +| AP4_AtomFinder ++---------------------------------------------------------------------*/ +class AP4_AtomFinder : public AP4_List<AP4_Atom>::Item::Finder +{ + public: + AP4_AtomFinder(AP4_Atom::Type type, AP4_Ordinal index = 0) : + m_Type(type), m_Index(index) {} + AP4_Result Test(AP4_Atom* atom) const { + if (atom->GetType() == m_Type) { + if (m_Index-- == 0) { + return AP4_SUCCESS; + } else { + return AP4_FAILURE; + } + } else { + return AP4_FAILURE; + } + } + private: + AP4_Atom::Type m_Type; + mutable AP4_Ordinal m_Index; +}; + +/*---------------------------------------------------------------------- +| AP4_AtomSizeAdder ++---------------------------------------------------------------------*/ +class AP4_AtomSizeAdder : public AP4_List<AP4_Atom>::Item::Operator { +public: + AP4_AtomSizeAdder(AP4_UI64& size) : m_Size(size) {} + +private: + AP4_Result Action(AP4_Atom* atom) const { + m_Size += atom->GetSize(); + return AP4_SUCCESS; + } + AP4_UI64& m_Size; +}; + +#endif // _AP4_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomFactory.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomFactory.cpp new file mode 100644 index 000000000..04158c4aa --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomFactory.cpp @@ -0,0 +1,774 @@ +/*****************************************************************
+|
+| AP4 - Atom Factory
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4Utils.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4SampleEntry.h"
+#include "Ap4UuidAtom.h"
+#include "Ap4IsmaCryp.h"
+#include "Ap4UrlAtom.h"
+#include "Ap4MoovAtom.h"
+#include "Ap4MvhdAtom.h"
+#include "Ap4MehdAtom.h"
+#include "Ap4MfhdAtom.h"
+#include "Ap4TfhdAtom.h"
+#include "Ap4TrunAtom.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4HdlrAtom.h"
+#include "Ap4DrefAtom.h"
+#include "Ap4TkhdAtom.h"
+#include "Ap4TrexAtom.h"
+#include "Ap4TfhdAtom.h"
+#include "Ap4MdhdAtom.h"
+#include "Ap4StsdAtom.h"
+#include "Ap4StscAtom.h"
+#include "Ap4StcoAtom.h"
+#include "Ap4Co64Atom.h"
+#include "Ap4StszAtom.h"
+#include "Ap4IodsAtom.h"
+#include "Ap4EsdsAtom.h"
+#include "Ap4SttsAtom.h"
+#include "Ap4CttsAtom.h"
+#include "Ap4StssAtom.h"
+#include "Ap4FtypAtom.h"
+#include "Ap4VmhdAtom.h"
+#include "Ap4SmhdAtom.h"
+#include "Ap4NmhdAtom.h"
+#include "Ap4HmhdAtom.h"
+#include "Ap4ElstAtom.h"
+#include "Ap4SchmAtom.h"
+#include "Ap4FrmaAtom.h"
+#include "Ap4TimsAtom.h"
+#include "Ap4RtpAtom.h"
+#include "Ap4SdpAtom.h"
+#include "Ap4IkmsAtom.h"
+#include "Ap4IsfmAtom.h"
+#include "Ap4IsltAtom.h"
+#include "Ap4OdheAtom.h"
+#include "Ap4OhdrAtom.h"
+#include "Ap4OddaAtom.h"
+#include "Ap4TrefTypeAtom.h"
+#include "Ap4MetaData.h"
+#include "Ap4IproAtom.h"
+#include "Ap4OdafAtom.h"
+#include "Ap4GrpiAtom.h"
+#include "Ap4AvccAtom.h"
+#include "Ap4Marlin.h"
+#include "Ap48bdlAtom.h"
+#include "Ap4Piff.h"
+#include "Ap4TfraAtom.h"
+#include "Ap4MfroAtom.h"
+
+// ==> Start patch MPC
+#include "Ap4ChplAtom.h"
+#include "Ap4FtabAtom.h"
+#include "Ap4DcomAtom.h"
+#include "AP4CmvdAtom.h"
+// <== End patch MPC
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::~AP4_AtomFactory
++---------------------------------------------------------------------*/
+AP4_AtomFactory::~AP4_AtomFactory()
+{
+ m_TypeHandlers.DeleteReferences();
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::AddTypeHandler
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomFactory::AddTypeHandler(TypeHandler* handler)
+{
+ return m_TypeHandlers.Add(handler);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::RemoveTypeHandler
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomFactory::RemoveTypeHandler(TypeHandler* handler)
+{
+ return m_TypeHandlers.Remove(handler);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::CreateAtomFromStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream,
+ AP4_Atom*& atom)
+{
+ AP4_LargeSize stream_size = 0;
+ AP4_Position stream_position = 0;
+ AP4_LargeSize bytes_available = (AP4_LargeSize)(-1);
+ if (AP4_SUCCEEDED(stream.GetSize(stream_size)) &&
+ stream_size != 0 &&
+ AP4_SUCCEEDED(stream.Tell(stream_position)) &&
+ stream_position <= stream_size) {
+ bytes_available = stream_size-stream_position;
+ }
+ return CreateAtomFromStream(stream, bytes_available, atom);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::CreateAtomFromStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream,
+ AP4_LargeSize& bytes_available,
+ AP4_Atom*& atom)
+{
+ AP4_Result result;
+
+ // NULL by default
+ atom = NULL;
+
+ // check that there are enough bytes for at least a header
+ if (bytes_available < 8) return AP4_ERROR_EOS;
+
+ // remember current stream offset
+ AP4_Position start;
+ stream.Tell(start);
+
+ // read atom size
+ AP4_UI32 size_32;
+ result = stream.ReadUI32(size_32);
+ if (AP4_FAILED(result)) {
+ stream.Seek(start);
+ return result;
+ }
+ AP4_UI64 size = size_32;
+
+ // read atom type
+ AP4_Atom::Type type;
+ result = stream.ReadUI32(type);
+ if (AP4_FAILED(result)) {
+ stream.Seek(start);
+ return result;
+ }
+
+ // handle special size values
+ bool atom_is_large = false;
+ bool force_64 = false;
+ if (size == 0) {
+ // atom extends to end of file
+ AP4_LargeSize stream_size = 0;
+ stream.GetSize(stream_size);
+ if (stream_size >= start) {
+ size = stream_size - start;
+ }
+ } else if (size == 1) {
+ // 64-bit size
+ atom_is_large = true;
+ if (bytes_available < 16) {
+ stream.Seek(start);
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+ stream.ReadUI64(size);
+ if (size <= 0xFFFFFFFF) {
+ force_64 = true;
+ }
+ }
+
+ // check the size
+ if ((size > 0 && size < 8) || size > bytes_available) {
+ stream.Seek(start);
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // create the atom
+ if (GetContext() == AP4_ATOM_TYPE_STSD) {
+ // sample entry
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ switch (type) {
+ case AP4_ATOM_TYPE_MP4A:
+ atom = new AP4_Mp4aSampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_MP4V:
+ atom = new AP4_Mp4vSampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_MP4S:
+ atom = new AP4_Mp4sSampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_ENCA:
+ atom = new AP4_EncaSampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_ENCV:
+ atom = new AP4_EncvSampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_DRMS:
+ atom = new AP4_DrmsSampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_DRMI:
+ atom = new AP4_DrmiSampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_AVC1:
+ atom = new AP4_Avc1SampleEntry(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_ALAC:
+ // ==> Start patch MPC
+// case AP4_ATOM_TYPE_AC_3:
+ // <== End patch MPC
+ case AP4_ATOM_TYPE_EC_3:
+ atom = new AP4_AudioSampleEntry(type, size_32, stream, *this);
+ break;
+
+ // ==> Start patch MPC
+ case AP4_ATOM_TYPE_TEXT:
+ atom = new AP4_TextSampleEntry((unsigned long)size, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_TX3G:
+ atom = new AP4_Tx3gSampleEntry((unsigned long)size, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_FTAB:
+ atom = new AP4_FtabAtom((unsigned long)size, stream);
+ break;
+
+ case AP4_ATOM_TYPE_CHPL:
+ atom = new AP4_ChplAtom((unsigned long)size, stream);
+ break;
+
+ case AP4_ATOM_TYPE_CVID:
+ case AP4_ATOM_TYPE_SVQ1:
+ case AP4_ATOM_TYPE_SVQ2:
+ case AP4_ATOM_TYPE_SVQ3:
+ case AP4_ATOM_TYPE_H263:
+ case AP4_ATOM_TYPE_S263:
+ atom = new AP4_VisualSampleEntry(type, (unsigned long)size, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_SAMR:
+ case AP4_ATOM_TYPE__MP3:
+ case AP4_ATOM_TYPE_IMA4:
+ case AP4_ATOM_TYPE_QDMC:
+ case AP4_ATOM_TYPE_QDM2:
+ case AP4_ATOM_TYPE_TWOS:
+ case AP4_ATOM_TYPE_SOWT:
+ atom = new AP4_AudioSampleEntry(type, (unsigned long)size, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_AC_3: // AC3-in-MP4 from ISO Standard
+ case AP4_ATOM_TYPE_SAC3: // AC3-in-MP4 from Nero Stuff >.<
+ atom = new AP4_AC3SampleEntry(type, (unsigned long)size, stream, *this);
+ break;
+ // <== End patch MPC
+
+ case AP4_ATOM_TYPE_RTP_:
+ atom = new AP4_RtpHintSampleEntry(size_32, stream, *this);
+ break;
+
+ default:
+ {
+ // try all the external type handlers
+ AP4_List<TypeHandler>::Item* handler_item = m_TypeHandlers.FirstItem();
+ while (handler_item) {
+ TypeHandler* handler = handler_item->GetData();
+ if (AP4_SUCCEEDED(handler->CreateAtom(type, size_32, stream, GetContext(), atom))) {
+ break;
+ }
+ handler_item = handler_item->GetNext();
+ }
+
+ // no custom handler, create a generic entry
+ atom = new AP4_UnknownSampleEntry(type, (AP4_Size)size, stream);
+ }
+ break;
+ }
+ } else {
+ // regular atom
+ switch (type) {
+ case AP4_ATOM_TYPE_MOOV:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_MoovAtom::Create(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_MVHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_MvhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_MEHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_MehdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_MFHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_MfhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_TRAK:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TrakAtom::Create(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_TREX:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TrexAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_HDLR:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_HdlrAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_TKHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TkhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_TFHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TfhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_TRUN:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TrunAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_TFRA:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TfraAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_MFRO:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_MfroAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_MDHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_MdhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_STSD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_StsdAtom::Create(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_STSC:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_StscAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_STCO:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_StcoAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_CO64:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_Co64Atom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_STSZ:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_StszAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_STTS:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_SttsAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_CTTS:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_CttsAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_STSS:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_StssAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_IODS:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_IodsAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_ESDS:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_EsdsAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_AVCC:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_AvccAtom::Create(size_32, stream);
+ break;
+
+ #if !defined(AP4_CONFIG_MINI_BUILD)
+ case AP4_ATOM_TYPE_UUID: {
+ AP4_UI08 uuid[16];
+ result = stream.Read(uuid, 16);
+ if (AP4_FAILED(result)) return result;
+
+ if (AP4_CompareMemory(uuid, AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, 16) == 0) {
+ atom = AP4_PiffTrackEncryptionAtom::Create((AP4_Size)size, stream);
+ } else if (AP4_CompareMemory(uuid, AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM, 16) == 0) {
+ atom = AP4_PiffSampleEncryptionAtom::Create((AP4_Size)size, stream);
+ } else {
+ atom = new AP4_UnknownUuidAtom(size, uuid, stream);
+ }
+ break;
+ }
+
+ case AP4_ATOM_TYPE_8ID_:
+ atom = new AP4_NullTerminatedStringAtom(type, size, stream);
+ break;
+
+ case AP4_ATOM_TYPE_8BDL:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_8bdlAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_DREF:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_DrefAtom::Create(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_URL:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_UrlAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_ELST:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_ElstAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_VMHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_VmhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_SMHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_SmhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_NMHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_NmhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_HMHD:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_HmhdAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_FRMA:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_FrmaAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_SCHM:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_SchmAtom::Create(size_32, &m_ContextStack, stream);
+ break;
+
+ case AP4_ATOM_TYPE_FTYP:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_FtypAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_TIMS:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TimsAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_SDP_:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_SdpAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_IKMS:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_IkmsAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_ISFM:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_IsfmAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_ISLT:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_IsltAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_ODHE:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_OdheAtom::Create(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_OHDR:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_OhdrAtom::Create(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_ODDA:
+ atom = AP4_OddaAtom::Create(size, stream);
+ break;
+
+ case AP4_ATOM_TYPE_ODAF:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_OdafAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_GRPI:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_GrpiAtom::Create(size_32, stream);
+ break;
+
+ case AP4_ATOM_TYPE_IPRO:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_IproAtom::Create(size_32, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_RTP_:
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_RtpAtom::Create(size_32, stream);
+ break;
+
+ // track ref types
+ case AP4_ATOM_TYPE_HINT:
+ case AP4_ATOM_TYPE_CDSC:
+ case AP4_ATOM_TYPE_SYNC:
+ case AP4_ATOM_TYPE_MPOD:
+ case AP4_ATOM_TYPE_DPND:
+ case AP4_ATOM_TYPE_IPIR:
+ case AP4_ATOM_TYPE_ALIS:
+ case AP4_ATOM_TYPE_CHAP:
+ if (GetContext() == AP4_ATOM_TYPE_TREF) {
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_TrefTypeAtom::Create(type, size_32, stream);
+ }
+ break;
+
+ #endif // AP4_CONFIG_MINI_BUILD
+
+ // container atoms
+ case AP4_ATOM_TYPE_MOOF:
+ case AP4_ATOM_TYPE_MVEX:
+ case AP4_ATOM_TYPE_TRAF:
+ case AP4_ATOM_TYPE_TREF:
+ case AP4_ATOM_TYPE_MFRA:
+ case AP4_ATOM_TYPE_HNTI:
+ case AP4_ATOM_TYPE_STBL:
+ case AP4_ATOM_TYPE_MDIA:
+ case AP4_ATOM_TYPE_DINF:
+ case AP4_ATOM_TYPE_MINF:
+ case AP4_ATOM_TYPE_SCHI:
+ case AP4_ATOM_TYPE_SINF:
+ case AP4_ATOM_TYPE_UDTA:
+ case AP4_ATOM_TYPE_ILST:
+ case AP4_ATOM_TYPE_EDTS:
+ case AP4_ATOM_TYPE_MDRI:
+ case AP4_ATOM_TYPE_WAVE:
+
+ // ==> Start patch MPC
+ case AP4_ATOM_TYPE_ART:
+ case AP4_ATOM_TYPE_WRT:
+ case AP4_ATOM_TYPE_ALB:
+ case AP4_ATOM_TYPE_DAY:
+ case AP4_ATOM_TYPE_TOO:
+ case AP4_ATOM_TYPE_CMT:
+ case AP4_ATOM_TYPE_GEN:
+ case AP4_ATOM_TYPE_CMOV:
+ // <== End patch MPC
+
+ if (atom_is_large) return AP4_ERROR_INVALID_FORMAT;
+ atom = AP4_ContainerAtom::Create(type, size, false, force_64, stream, *this);
+ break;
+
+ // full container atoms
+ case AP4_ATOM_TYPE_META:
+ case AP4_ATOM_TYPE_ODRM:
+ case AP4_ATOM_TYPE_ODKM:
+ atom = AP4_ContainerAtom::Create(type, size, true, force_64, stream, *this);
+ break;
+
+ case AP4_ATOM_TYPE_FREE:
+ case AP4_ATOM_TYPE_WIDE:
+ case AP4_ATOM_TYPE_MDAT:
+ // generic atoms
+ break;
+
+ // ==> Start patch MPC
+ case AP4_ATOM_TYPE_DCOM:
+ atom = AP4_DcomAtom::Create((unsigned long)size, stream);
+ break;
+ case AP4_ATOM_TYPE_CMVD:
+ atom = AP4_CmvdAtom::Create((unsigned long)size, stream, *this);
+ break;
+ // <== End patch MPC
+
+ default:
+ // try all the external type handlers
+ {
+ AP4_List<TypeHandler>::Item* handler_item = m_TypeHandlers.FirstItem();
+ while (handler_item) {
+ TypeHandler* handler = handler_item->GetData();
+ if (AP4_SUCCEEDED(handler->CreateAtom(type, size_32, stream, GetContext(), atom))) {
+ break;
+ }
+ handler_item = handler_item->GetNext();
+ }
+
+ break;
+ }
+ }
+ }
+
+ // if we failed to create an atom, use a generic version
+ if (atom == NULL) {
+ unsigned int payload_offset = 8;
+ if (atom_is_large) payload_offset += 8;
+ stream.Seek(start+payload_offset);
+ atom = new AP4_UnknownAtom(type, size, stream);
+ }
+
+ // special case: if the atom is poorly encoded and has a 64-bit
+ // size header but an actual size that fits on 32-bit, adjust the
+ // object to reflect that.
+ if (force_64) {
+ atom->SetSize32(1);
+ atom->SetSize64(size);
+ }
+
+ // adjust the available size
+ bytes_available -= size;
+
+ // skip to the end of the atom
+ result = stream.Seek(start+size);
+ if (AP4_FAILED(result)) {
+ delete atom;
+ atom = NULL;
+ return result;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::CreateAtomsFromStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomFactory::CreateAtomsFromStream(AP4_ByteStream& stream,
+ AP4_AtomParent& atoms)
+{
+ AP4_LargeSize stream_size = 0;
+ AP4_Position stream_position = 0;
+ AP4_LargeSize bytes_available = (AP4_LargeSize)(-1);
+ if (AP4_SUCCEEDED(stream.GetSize(stream_size)) &&
+ stream_size != 0 &&
+ AP4_SUCCEEDED(stream.Tell(stream_position)) &&
+ stream_position <= stream_size) {
+ bytes_available = stream_size-stream_position;
+ }
+ return CreateAtomsFromStream(stream, bytes_available, atoms);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::CreateAtomsFromStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomFactory::CreateAtomsFromStream(AP4_ByteStream& stream,
+ AP4_LargeSize bytes_available,
+ AP4_AtomParent& atoms)
+{
+ AP4_Result result;
+ do {
+ AP4_Atom* atom = NULL;
+ result = CreateAtomFromStream(stream, bytes_available, atom);
+ if (AP4_SUCCEEDED(result) && atom != NULL) {
+ atoms.AddChild(atom);
+ }
+ } while (AP4_SUCCEEDED(result));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::PushContext
++---------------------------------------------------------------------*/
+void
+AP4_AtomFactory::PushContext(AP4_Atom::Type context)
+{
+ m_ContextStack.Append(context);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::PopContext
++---------------------------------------------------------------------*/
+void
+AP4_AtomFactory::PopContext()
+{
+ m_ContextStack.RemoveLast();
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomFactory::GetContext
++---------------------------------------------------------------------*/
+AP4_Atom::Type
+AP4_AtomFactory::GetContext(AP4_Ordinal depth)
+{
+ AP4_Ordinal available = m_ContextStack.ItemCount();
+ if (depth >= available) return 0;
+ return m_ContextStack[available-depth-1];
+}
+
+/*----------------------------------------------------------------------
+| AP4_DefaultAtomFactory::Instance
++---------------------------------------------------------------------*/
+AP4_DefaultAtomFactory AP4_DefaultAtomFactory::Instance;
+
+/*----------------------------------------------------------------------
+| AP4_DefaultAtomFactory::Instance
++---------------------------------------------------------------------*/
+AP4_DefaultAtomFactory::AP4_DefaultAtomFactory()
+{
+ // register built-in type handlers
+ AddTypeHandler(new AP4_MetaDataAtomTypeHandler(this));
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomFactory.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomFactory.h new file mode 100644 index 000000000..3c7486a7c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomFactory.h @@ -0,0 +1,103 @@ +/***************************************************************** +| +| AP4 - Atom Factory +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_ATOM_FACTORY_H_ +#define _AP4_ATOM_FACTORY_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_AtomFactory ++---------------------------------------------------------------------*/ +class AP4_AtomFactory { + public: + // types + class TypeHandler { + public: + virtual ~TypeHandler() {}; + virtual AP4_Result CreateAtom(AP4_Atom::Type type, + AP4_UI32 size, + AP4_ByteStream& stream, + AP4_Atom::Type context, + AP4_Atom*& atom) = 0; + }; + + // constructor + AP4_AtomFactory() {} + + // destructor + ~AP4_AtomFactory(); + + // methods + AP4_Result AddTypeHandler(TypeHandler* handler); + AP4_Result RemoveTypeHandler(TypeHandler* handler); + AP4_Result CreateAtomFromStream(AP4_ByteStream& stream, + AP4_LargeSize& bytes_available, + AP4_Atom*& atom); + AP4_Result CreateAtomFromStream(AP4_ByteStream& stream, + AP4_Atom*& atom); + AP4_Result CreateAtomsFromStream(AP4_ByteStream& stream, + AP4_AtomParent& atoms); + AP4_Result CreateAtomsFromStream(AP4_ByteStream& stream, + AP4_LargeSize bytes_available, + AP4_AtomParent& atoms); + + // context + void PushContext(AP4_Atom::Type context); + void PopContext(); + AP4_Atom::Type GetContext(AP4_Ordinal depth=0); + +private: + // members + AP4_Array<AP4_Atom::Type> m_ContextStack; + AP4_List<TypeHandler> m_TypeHandlers; +}; + +/*---------------------------------------------------------------------- +| AP4_DefaultAtomFactory ++---------------------------------------------------------------------*/ +class AP4_DefaultAtomFactory : public AP4_AtomFactory { +public: + // class members + static AP4_DefaultAtomFactory Instance; + + // constructor + AP4_DefaultAtomFactory(); +}; + +#endif // _AP4_ATOM_FACTORY_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomSampleTable.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomSampleTable.cpp new file mode 100644 index 000000000..732ca2ef2 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomSampleTable.cpp @@ -0,0 +1,373 @@ +/*****************************************************************
+|
+| AP4 - Atom Based Sample Tables
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This atom is part of AP4 (MP4 Audio Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the atom COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4AtomSampleTable.h"
+#include "Ap4ByteStream.h"
+#include "Ap4StsdAtom.h"
+#include "Ap4StscAtom.h"
+#include "Ap4StcoAtom.h"
+#include "Ap4Co64Atom.h"
+#include "Ap4StszAtom.h"
+#include "Ap4SttsAtom.h"
+#include "Ap4CttsAtom.h"
+#include "Ap4StssAtom.h"
+#include "Ap4Sample.h"
+#include "Ap4Atom.h"
+
+// ==> Start patch MPC
+#include "Ap4SampleEntry.h"
+// <== End patch MPC
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::AP4_AtomSampleTable
++---------------------------------------------------------------------*/
+AP4_AtomSampleTable::AP4_AtomSampleTable(AP4_ContainerAtom* stbl,
+ AP4_ByteStream& sample_stream) :
+ m_SampleStream(sample_stream)
+{
+ m_StscAtom = AP4_DYNAMIC_CAST(AP4_StscAtom, stbl->GetChild(AP4_ATOM_TYPE_STSC));
+ m_StcoAtom = AP4_DYNAMIC_CAST(AP4_StcoAtom, stbl->GetChild(AP4_ATOM_TYPE_STCO));
+ m_StszAtom = AP4_DYNAMIC_CAST(AP4_StszAtom, stbl->GetChild(AP4_ATOM_TYPE_STSZ));
+ m_CttsAtom = AP4_DYNAMIC_CAST(AP4_CttsAtom, stbl->GetChild(AP4_ATOM_TYPE_CTTS));
+ m_SttsAtom = AP4_DYNAMIC_CAST(AP4_SttsAtom, stbl->GetChild(AP4_ATOM_TYPE_STTS));
+ m_StssAtom = AP4_DYNAMIC_CAST(AP4_StssAtom, stbl->GetChild(AP4_ATOM_TYPE_STSS));
+ m_StsdAtom = AP4_DYNAMIC_CAST(AP4_StsdAtom, stbl->GetChild(AP4_ATOM_TYPE_STSD));
+ m_Co64Atom = AP4_DYNAMIC_CAST(AP4_Co64Atom, stbl->GetChild(AP4_ATOM_TYPE_CO64));
+
+ // keep a reference to the sample stream
+ m_SampleStream.AddReference();
+
+ // ==> Start patch MPC
+ if(m_StsdAtom && m_StszAtom && m_StscAtom && m_SttsAtom
+ && m_StszAtom->m_SampleSize == 1)
+ {
+ // fix mov files
+ for(AP4_List<AP4_Atom>::Item* item = m_StsdAtom->GetChildren().FirstItem();
+ item;
+ item = item->GetNext())
+ {
+ AP4_Atom* atom = item->GetData();
+
+ if(AP4_AudioSampleEntry* ase = dynamic_cast<AP4_AudioSampleEntry*>(atom))
+ {
+ AP4_UI32 SamplesPerPacket = ase->GetSamplesPerPacket();
+ AP4_UI32 BytesPerFrame = ase->GetBytesPerFrame();
+
+ if(SamplesPerPacket > 0 && BytesPerFrame > 0)
+ {
+ for(int i = 0, j = m_StscAtom->m_Entries.ItemCount(); i < j; i++)
+ {
+ AP4_StscTableEntry& e = m_StscAtom->m_Entries[i];
+ AP4_ASSERT(e.m_SamplesPerChunk % SamplesPerPacket == 0);
+ e.m_SamplesPerChunk = e.m_SamplesPerChunk / SamplesPerPacket;
+ e.m_FirstSample = (e.m_FirstSample-1) / SamplesPerPacket + 1;
+ }
+
+ AP4_ASSERT(m_StszAtom->m_SampleCount % SamplesPerPacket == 0);
+ m_StszAtom->m_SampleCount = m_StszAtom->m_SampleCount / SamplesPerPacket;
+ m_StszAtom->m_SampleSize = BytesPerFrame;
+
+ AP4_ASSERT(m_SttsAtom->m_Entries.ItemCount() == 1);
+ m_SttsAtom->m_Entries[0].m_SampleCount = m_StszAtom->m_SampleCount;
+ m_SttsAtom->m_Entries[0].m_SampleDuration = SamplesPerPacket;
+ }
+ }
+ }
+ }
+ // <== End patch MPC
+
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::~AP4_AtomSampleTable
++---------------------------------------------------------------------*/
+AP4_AtomSampleTable::~AP4_AtomSampleTable()
+{
+ m_SampleStream.Release();
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomSampleTable::GetSample(AP4_Ordinal index,
+ AP4_Sample& sample)
+{
+ AP4_Result result;
+
+ // check that we have a chunk offset table
+ if (m_StcoAtom == NULL && m_Co64Atom == NULL) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // MP4 uses 1-based indexes internally, so adjust by one
+ index++;
+
+ // find out in which chunk this sample is located
+ AP4_Ordinal chunk, skip, desc;
+ result = m_StscAtom->GetChunkForSample(index, chunk, skip, desc);
+ if (AP4_FAILED(result)) return result;
+
+ // check that the result is within bounds
+ if (skip > index) return AP4_ERROR_INTERNAL;
+
+ // get the atom offset for this chunk
+ AP4_UI64 offset;
+ if (m_StcoAtom) {
+ AP4_UI32 offset_32;
+ result = m_StcoAtom->GetChunkOffset(chunk, offset_32);
+ offset = offset_32;
+ } else {
+ result = m_Co64Atom->GetChunkOffset(chunk, offset);
+ }
+ if (AP4_FAILED(result)) return result;
+
+ // compute the additional offset inside the chunk
+ for (unsigned int i = index-skip; i < index; i++) {
+ AP4_Size size;
+ result = m_StszAtom->GetSampleSize(i, size);
+ if (AP4_FAILED(result)) return result;
+ offset += size;
+ }
+
+ // set the description index
+ sample.SetDescriptionIndex(desc-1); // adjust for 0-based indexes
+
+ // set the dts and cts
+ AP4_UI32 cts_offset = 0;
+ AP4_UI64 dts = 0;
+ AP4_UI32 duration = 0;
+ result = m_SttsAtom->GetDts(index, dts, &duration);
+ if (AP4_FAILED(result)) return result;
+ sample.SetDuration(duration);
+ sample.SetDts(dts);
+ if (m_CttsAtom == NULL) {
+ sample.SetCts(dts);
+ } else {
+ result = m_CttsAtom->GetCtsOffset(index, cts_offset);
+ if (AP4_FAILED(result)) return result;
+ sample.SetCtsDelta(cts_offset);
+ }
+
+ // set the size
+ AP4_Size sample_size;
+ result = m_StszAtom->GetSampleSize(index, sample_size);
+ if (AP4_FAILED(result)) return result;
+ sample.SetSize(sample_size);
+
+ // set the sync flag
+ if (m_StssAtom == NULL) {
+ sample.SetSync(true);
+ } else {
+ sample.SetSync(m_StssAtom->IsSampleSync(index));
+ }
+
+ // set the offset
+ sample.SetOffset(offset);
+
+ // set the data stream
+ sample.SetDataStream(m_SampleStream);
+
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetSampleCount
++---------------------------------------------------------------------*/
+AP4_Cardinal
+AP4_AtomSampleTable::GetSampleCount()
+{
+ return m_StszAtom ? m_StszAtom->GetSampleCount() : 0;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetSampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_AtomSampleTable::GetSampleDescription(AP4_Ordinal index)
+{
+ return m_StsdAtom ? m_StsdAtom->GetSampleDescription(index) : NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetSampleDescriptionCount
++---------------------------------------------------------------------*/
+AP4_Cardinal
+AP4_AtomSampleTable::GetSampleDescriptionCount()
+{
+ return m_StsdAtom ? m_StsdAtom->GetSampleDescriptionCount() : 0;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetSampleChunkPosition
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomSampleTable::GetSampleChunkPosition(AP4_Ordinal sample_index,
+ AP4_Ordinal& chunk_index,
+ AP4_Ordinal& position_in_chunk)
+{
+ // default values
+ chunk_index = 0;
+ position_in_chunk = 0;
+
+ AP4_Ordinal sample_description_index;
+ return GetChunkForSample(sample_index,
+ chunk_index,
+ position_in_chunk,
+ sample_description_index);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetChunkForSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomSampleTable::GetChunkForSample(AP4_Ordinal sample_index,
+ AP4_Ordinal& chunk_index,
+ AP4_Ordinal& position_in_chunk,
+ AP4_Ordinal& sample_description_index)
+{
+ // default values
+ chunk_index = 0;
+ position_in_chunk = 0;
+ sample_description_index = 0;
+
+ // check that we an stsc atom
+ if (m_StscAtom == NULL) return AP4_ERROR_INVALID_STATE;
+
+ // get the chunk info from the stsc atom
+ AP4_Ordinal chunk = 0;
+ AP4_Result result = m_StscAtom->GetChunkForSample(sample_index+1, // the atom API is 1-based
+ chunk,
+ position_in_chunk,
+ sample_description_index);
+ if (AP4_FAILED(result)) return result;
+ if (chunk == 0) return AP4_ERROR_INTERNAL;
+
+ // the atom sample and chunk indexes are 1-based, so we need to translate
+ chunk_index = chunk-1;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetChunkOffset
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomSampleTable::GetChunkOffset(AP4_Ordinal chunk_index,
+ AP4_Position& offset)
+{
+ if (m_StcoAtom) {
+ AP4_UI32 offset_32;
+ AP4_Result result = m_StcoAtom->GetChunkOffset(chunk_index+1, offset_32);
+ if (AP4_SUCCEEDED(result)) {
+ offset = offset_32;
+ } else {
+ offset = 0;
+ }
+ return result;
+ } else if (m_Co64Atom) {
+ return m_Co64Atom->GetChunkOffset(chunk_index+1, offset);
+ } else {
+ offset = 0;
+ return AP4_FAILURE;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::SetChunkOffset
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomSampleTable::SetChunkOffset(AP4_Ordinal chunk_index,
+ AP4_Position offset)
+{
+ if (m_StcoAtom) {
+ if ((offset >> 32) != 0) return AP4_ERROR_OUT_OF_RANGE;
+ return m_StcoAtom->SetChunkOffset(chunk_index+1, (AP4_UI32)offset);
+ } else if (m_Co64Atom) {
+ return m_Co64Atom->SetChunkOffset(chunk_index+1, offset);
+ } else {
+ return AP4_FAILURE;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::SetSampleSize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomSampleTable::SetSampleSize(AP4_Ordinal sample_index, AP4_Size size)
+{
+ return m_StszAtom ? m_StszAtom->SetSampleSize(sample_index+1, size) : AP4_FAILURE;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetSampleIndexForTimeStamp
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomSampleTable::GetSampleIndexForTimeStamp(AP4_UI64 ts,
+ AP4_Ordinal& sample_index)
+{
+ return m_SttsAtom ? m_SttsAtom->GetSampleIndexForTimeStamp(ts, sample_index)
+ : AP4_FAILURE;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable::GetNearestSyncSampleIndex
++---------------------------------------------------------------------*/
+AP4_Ordinal
+AP4_AtomSampleTable::GetNearestSyncSampleIndex(AP4_Ordinal sample_index, bool before)
+{
+ // if we don't have an stss table, all samples match
+ if (m_StssAtom == NULL) return sample_index;
+
+ sample_index += 1; // the table is 1-based
+ AP4_Cardinal entry_count = m_StssAtom->GetEntries().ItemCount();
+ if (before) {
+ AP4_Ordinal cursor = 0;
+ for (unsigned int i=0; i<entry_count; i++) {
+ if (m_StssAtom->GetEntries()[i] >= sample_index) return cursor;
+ if (m_StssAtom->GetEntries()[i]) cursor = m_StssAtom->GetEntries()[i]-1;
+ }
+
+ // not found?
+ return cursor;
+ } else {
+ for (unsigned int i=0; i<entry_count; i++) {
+ if (m_StssAtom->GetEntries()[i] >= sample_index) {
+ return m_StssAtom->GetEntries()[i]?m_StssAtom->GetEntries()[i]-1:sample_index-1;
+ }
+ }
+
+ // not found?
+ return GetSampleCount();
+ }
+}
+
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomSampleTable.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomSampleTable.h new file mode 100644 index 000000000..aaecbf917 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AtomSampleTable.h @@ -0,0 +1,96 @@ +/*****************************************************************
+|
+| AP4 - Atom Based Sample Table
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This atom is part of AP4 (MP4 Audio Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the atom COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_ATOM_SAMPLE_TABLE_H_
+#define _AP4_ATOM_SAMPLE_TABLE_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4SampleTable.h"
+
+/*----------------------------------------------------------------------
+| forward declarations
++---------------------------------------------------------------------*/
+class AP4_Atom;
+class AP4_ByteStream;
+class AP4_StscAtom;
+class AP4_StcoAtom;
+class AP4_StszAtom;
+class AP4_SttsAtom;
+class AP4_CttsAtom;
+class AP4_StssAtom;
+class AP4_StsdAtom;
+class AP4_Co64Atom;
+
+/*----------------------------------------------------------------------
+| AP4_AtomSampleTable
++---------------------------------------------------------------------*/
+class AP4_AtomSampleTable : public AP4_SampleTable
+{
+ public:
+ // methods
+ AP4_AtomSampleTable(AP4_ContainerAtom* stbl_atom,
+ AP4_ByteStream& sample_stream);
+ virtual ~AP4_AtomSampleTable();
+
+ // AP4_SampleTable methods
+ virtual AP4_Result GetSample(AP4_Ordinal sample_index, AP4_Sample& sample);
+ virtual AP4_Cardinal GetSampleCount();
+ virtual AP4_SampleDescription* GetSampleDescription(AP4_Ordinal sd_index);
+ virtual AP4_Cardinal GetSampleDescriptionCount();
+ virtual AP4_Result GetSampleChunkPosition(AP4_Ordinal sample_index,
+ AP4_Ordinal& chunk_index,
+ AP4_Ordinal& position_in_chunk);
+ virtual AP4_Result GetSampleIndexForTimeStamp(AP4_UI64 ts, AP4_Ordinal& sample_index);
+ virtual AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal index, bool before=true);
+
+ // local methods
+ virtual AP4_Result GetChunkForSample(AP4_Ordinal sample_index,
+ AP4_Ordinal& chunk_index,
+ AP4_Ordinal& position_in_chunk,
+ AP4_Ordinal& sample_description_index);
+ virtual AP4_Result GetChunkOffset(AP4_Ordinal chunk_index, AP4_Position& offset);
+ virtual AP4_Result SetChunkOffset(AP4_Ordinal chunk_index, AP4_Position offset);
+ virtual AP4_Result SetSampleSize(AP4_Ordinal sample_index, AP4_Size size);
+
+private:
+ // members
+ AP4_ByteStream& m_SampleStream;
+ AP4_StscAtom* m_StscAtom;
+ AP4_StcoAtom* m_StcoAtom;
+ AP4_StszAtom* m_StszAtom;
+ AP4_SttsAtom* m_SttsAtom;
+ AP4_CttsAtom* m_CttsAtom;
+ AP4_StsdAtom* m_StsdAtom;
+ AP4_StssAtom* m_StssAtom;
+ AP4_Co64Atom* m_Co64Atom;
+};
+
+#endif // _AP4_ATOM_SAMPLE_TABLE_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AvcCAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AvcCAtom.cpp new file mode 100644 index 000000000..ac227203d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AvcCAtom.cpp @@ -0,0 +1,277 @@ +/*****************************************************************
+|
+| AP4 - avcC Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4AvccAtom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4Utils.h"
+#include "Ap4Types.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_AvccAtom)
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::GetProfileName
++---------------------------------------------------------------------*/
+const char*
+AP4_AvccAtom::GetProfileName(AP4_UI08 profile)
+{
+ switch (profile) {
+ case AP4_AVC_PROFILE_BASELINE: return "Baseline";
+ case AP4_AVC_PROFILE_MAIN: return "Main";
+ case AP4_AVC_PROFILE_EXTENDED: return "Extended";
+ case AP4_AVC_PROFILE_HIGH: return "High";
+ case AP4_AVC_PROFILE_HIGH_10: return "High 10";
+ case AP4_AVC_PROFILE_HIGH_422: return "High 4:2:2";
+ case AP4_AVC_PROFILE_HIGH_444: return "High 4:4:4";
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::Create
++---------------------------------------------------------------------*/
+AP4_AvccAtom*
+AP4_AvccAtom::Create(AP4_Size size, AP4_ByteStream& stream)
+{
+ // read the raw bytes in a buffer
+ unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
+ AP4_DataBuffer payload_data(payload_size);
+ AP4_Result result = stream.Read(payload_data.UseData(), payload_size);
+ if (AP4_FAILED(result)) return NULL;
+
+ // check the version
+ const AP4_UI08* payload = payload_data.GetData();
+ if (payload[0] != 1) {
+ return NULL;
+ }
+
+ // check the size
+ if (payload_size < 6) return NULL;
+ unsigned int num_seq_params = payload[5]&31;
+ unsigned int cursor = 6;
+ for (unsigned int i=0; i<num_seq_params; i++) {
+ if (cursor+2 > payload_size) return NULL;
+ cursor += 2+AP4_BytesToInt16BE(&payload[cursor]);
+ if (cursor > payload_size) return NULL;
+ }
+ unsigned int num_pic_params = payload[cursor++];
+ if (cursor > payload_size) return NULL;
+ for (unsigned int i=0; i<num_pic_params; i++) {
+ if (cursor+2 > payload_size) return NULL;
+ cursor += 2+AP4_BytesToInt16BE(&payload[cursor]);
+ if (cursor > payload_size) return NULL;
+ }
+ return new AP4_AvccAtom(size, payload);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::AP4_AvccAtom
++---------------------------------------------------------------------*/
+AP4_AvccAtom::AP4_AvccAtom() :
+ AP4_Atom(AP4_ATOM_TYPE_AVCC, AP4_ATOM_HEADER_SIZE),
+ m_ConfigurationVersion(1),
+ m_Profile(0),
+ m_Level(0),
+ m_ProfileCompatibility(0),
+ m_NaluLengthSize(0)
+{
+ UpdateRawBytes();
+ m_Size32 += m_RawBytes.GetDataSize();
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::AP4_AvccAtom
++---------------------------------------------------------------------*/
+AP4_AvccAtom::AP4_AvccAtom(const AP4_AvccAtom& other) :
+ AP4_Atom(AP4_ATOM_TYPE_AVCC, other.m_Size32),
+ m_ConfigurationVersion(other.m_ConfigurationVersion),
+ m_Profile(other.m_Profile),
+ m_Level(other.m_Level),
+ m_ProfileCompatibility(other.m_ProfileCompatibility),
+ m_NaluLengthSize(other.m_NaluLengthSize),
+ m_RawBytes(other.m_RawBytes)
+{
+ // deep copy of the parameters
+ unsigned int i = 0;
+ for (i=0; i<other.m_SequenceParameters.ItemCount(); i++) {
+ m_SequenceParameters.Append(other.m_SequenceParameters[i]);
+ }
+ for (i=0; i<other.m_PictureParameters.ItemCount(); i++) {
+ m_PictureParameters.Append(other.m_PictureParameters[i]);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::AP4_AvccAtom
++---------------------------------------------------------------------*/
+AP4_AvccAtom::AP4_AvccAtom(AP4_UI32 size, const AP4_UI08* payload) :
+ AP4_Atom(AP4_ATOM_TYPE_AVCC, size)
+{
+ // make a copy of our configuration bytes
+ unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
+ m_RawBytes.SetData(payload, payload_size);
+
+ // parse the payload
+ m_ConfigurationVersion = payload[0];
+ m_Profile = payload[1];
+ m_ProfileCompatibility = payload[2];
+ m_Level = payload[3];
+ m_NaluLengthSize = 1+(payload[4]&3);
+ AP4_UI08 num_seq_params = payload[5]&31;
+ m_SequenceParameters.EnsureCapacity(num_seq_params);
+ unsigned int cursor = 6;
+ for (unsigned int i=0; i<num_seq_params; i++) {
+ m_SequenceParameters.Append(AP4_DataBuffer());
+ AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]);
+ m_SequenceParameters[i].SetData(&payload[cursor]+2, param_length);
+ cursor += 2+param_length;
+ }
+ AP4_UI08 num_pic_params = payload[cursor++];
+ m_PictureParameters.EnsureCapacity(num_pic_params);
+ for (unsigned int i=0; i<num_pic_params; i++) {
+ m_PictureParameters.Append(AP4_DataBuffer());
+ AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]);
+ m_PictureParameters[i].SetData(&payload[cursor]+2, param_length);
+ cursor += 2+param_length;
+ }
+}
+
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::AP4_AvccAtom
++---------------------------------------------------------------------*/
+AP4_AvccAtom::AP4_AvccAtom(AP4_UI08 profile,
+ AP4_UI08 level,
+ AP4_UI08 profile_compatibility,
+ AP4_UI08 length_size,
+ const AP4_Array<AP4_DataBuffer>& sequence_parameters,
+ const AP4_Array<AP4_DataBuffer>& picture_parameters) :
+ AP4_Atom(AP4_ATOM_TYPE_AVCC, AP4_ATOM_HEADER_SIZE),
+ m_ConfigurationVersion(1),
+ m_Profile(profile),
+ m_Level(level),
+ m_ProfileCompatibility(profile_compatibility),
+ m_NaluLengthSize(length_size)
+{
+ // deep copy of the parameters
+ unsigned int i = 0;
+ for (i=0; i<sequence_parameters.ItemCount(); i++) {
+ m_SequenceParameters.Append(sequence_parameters[i]);
+ }
+ for (i=0; i<picture_parameters.ItemCount(); i++) {
+ m_PictureParameters.Append(picture_parameters[i]);
+ }
+
+ // compute the raw bytes
+ UpdateRawBytes();
+
+ // update the size
+ m_Size32 += m_RawBytes.GetDataSize();
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::UpdateRawBytes
++---------------------------------------------------------------------*/
+void
+AP4_AvccAtom::UpdateRawBytes()
+{
+ // compute the payload size
+ unsigned int payload_size = 6;
+ for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
+ payload_size += 2+m_SequenceParameters[i].GetDataSize();
+ }
+ ++payload_size;
+ for (unsigned int i=0; i<m_PictureParameters.ItemCount(); i++) {
+ payload_size += 2+m_PictureParameters[i].GetDataSize();
+ }
+ m_RawBytes.SetDataSize(payload_size);
+ AP4_UI08* payload = m_RawBytes.UseData();
+
+ payload[0] = m_ConfigurationVersion;
+ payload[1] = m_Profile;
+ payload[2] = m_ProfileCompatibility;
+ payload[3] = m_Level;
+ payload[4] = 0xFC | (m_NaluLengthSize-1);
+ payload[5] = 0xE0 | m_SequenceParameters.ItemCount();
+ unsigned int cursor = 6;
+ for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
+ AP4_UI16 param_length = (AP4_UI16)m_SequenceParameters[i].GetDataSize();
+ AP4_BytesFromUInt16BE(&payload[cursor], param_length);
+ cursor += 2;
+ AP4_CopyMemory(&payload[cursor], m_SequenceParameters[i].GetData(), param_length);
+ cursor += param_length;
+ }
+ payload[cursor++] = m_PictureParameters.ItemCount();
+ for (unsigned int i=0; i<m_PictureParameters.ItemCount(); i++) {
+ AP4_UI16 param_length = (AP4_UI16)m_PictureParameters[i].GetDataSize();
+ AP4_BytesFromUInt16BE(&payload[cursor], param_length);
+ cursor += 2;
+ AP4_CopyMemory(&payload[cursor], m_PictureParameters[i].GetData(), param_length);
+ cursor += param_length;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AvccAtom::WriteFields(AP4_ByteStream& stream)
+{
+ return stream.Write(m_RawBytes.GetData(), m_RawBytes.GetDataSize());
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AvccAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("Configuration Version", m_ConfigurationVersion);
+ const char* profile_name = GetProfileName(m_Profile);
+ if (profile_name) {
+ inspector.AddField("Profile", profile_name);
+ } else {
+ inspector.AddField("Profile", m_Profile);
+ }
+ inspector.AddField("Profile Compatibility", m_ProfileCompatibility, AP4_AtomInspector::HINT_HEX);
+ inspector.AddField("Level", m_Level);
+ inspector.AddField("NALU Length Size", m_NaluLengthSize);
+ for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
+ inspector.AddField("Sequence Parameter", m_SequenceParameters[i].GetData(), m_SequenceParameters[i].GetDataSize());
+ }
+ for (unsigned int i=0; i<m_SequenceParameters.ItemCount(); i++) {
+ inspector.AddField("Picture Parameter", m_PictureParameters[i].GetData(), m_PictureParameters[i].GetDataSize());
+ }
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AvcCAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AvcCAtom.h new file mode 100644 index 000000000..b3b300853 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4AvcCAtom.h @@ -0,0 +1,102 @@ +/*****************************************************************
+|
+| AP4 - avcC Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+#ifndef _AP4_AVCC_ATOM_H_
+#define _AP4_AVCC_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+#include "Ap4Array.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_UI08 AP4_AVC_PROFILE_BASELINE = 66;
+const AP4_UI08 AP4_AVC_PROFILE_MAIN = 77;
+const AP4_UI08 AP4_AVC_PROFILE_EXTENDED = 88;
+const AP4_UI08 AP4_AVC_PROFILE_HIGH = 100;
+const AP4_UI08 AP4_AVC_PROFILE_HIGH_10 = 110;
+const AP4_UI08 AP4_AVC_PROFILE_HIGH_422 = 122;
+const AP4_UI08 AP4_AVC_PROFILE_HIGH_444 = 144;
+
+
+/*----------------------------------------------------------------------
+| AP4_AvccAtom
++---------------------------------------------------------------------*/
+class AP4_AvccAtom : public AP4_Atom
+{
+public:
+ AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_AvccAtom, AP4_Atom)
+
+ // class methods
+ static AP4_AvccAtom* Create(AP4_Size size, AP4_ByteStream& stream);
+ static const char* GetProfileName(AP4_UI08 profile);
+
+ // constructors
+ AP4_AvccAtom();
+ AP4_AvccAtom(AP4_UI08 profile,
+ AP4_UI08 level,
+ AP4_UI08 profile_compatibility,
+ AP4_UI08 length_size,
+ const AP4_Array<AP4_DataBuffer>& sequence_parameters,
+ const AP4_Array<AP4_DataBuffer>& picture_parameters);
+ AP4_AvccAtom(const AP4_AvccAtom& other); // copy construtor
+
+ // methods
+ virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
+ virtual AP4_Result WriteFields(AP4_ByteStream& stream);
+
+ // accessors
+ AP4_UI08 GetConfigurationVersion() const { return m_ConfigurationVersion; }
+ AP4_UI08 GetProfile() const { return m_Profile; }
+ AP4_UI08 GetLevel() const { return m_Level; }
+ AP4_UI08 GetProfileCompatibility() const { return m_ProfileCompatibility; }
+ AP4_UI08 GetNaluLengthSize() const { return m_NaluLengthSize; }
+ AP4_Array<AP4_DataBuffer>& GetSequenceParameters() { return m_SequenceParameters; }
+ AP4_Array<AP4_DataBuffer>& GetPictureParameters() { return m_PictureParameters; }
+ const AP4_DataBuffer& GetRawBytes() const { return m_RawBytes; }
+
+private:
+ // methods
+ AP4_AvccAtom(AP4_UI32 size, const AP4_UI08* payload);
+ void UpdateRawBytes();
+
+ // members
+ AP4_UI08 m_ConfigurationVersion;
+ AP4_UI08 m_Profile;
+ AP4_UI08 m_Level;
+ AP4_UI08 m_ProfileCompatibility;
+ AP4_UI08 m_NaluLengthSize;
+ AP4_Array<AP4_DataBuffer> m_SequenceParameters;
+ AP4_Array<AP4_DataBuffer> m_PictureParameters;
+ AP4_DataBuffer m_RawBytes;
+};
+
+#endif // _AP4_AVCC_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ByteStream.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ByteStream.cpp new file mode 100644 index 000000000..e5c33d319 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ByteStream.cpp @@ -0,0 +1,842 @@ +/*****************************************************************
+|
+| AP4 - Byte Stream support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4ByteStream.h"
+#include "Ap4Utils.h"
+#include "Ap4Debug.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const int AP4_BYTE_STREAM_COPY_BUFFER_SIZE = 65536;
+const int AP4_MEMORY_BYTE_STREAM_MAX_SIZE = 0x4000000; // 64 megs
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::Read
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::Read(void* buffer, AP4_Size bytes_to_read)
+{
+ // shortcut
+ if (bytes_to_read == 0) return AP4_SUCCESS;
+
+ // read until failure
+ AP4_Size bytes_read;
+ while (bytes_to_read) {
+ AP4_Result result = ReadPartial(buffer, bytes_to_read, bytes_read);
+ if (AP4_FAILED(result)) return result;
+ if (bytes_read == 0) return AP4_ERROR_INTERNAL;
+ AP4_ASSERT(bytes_read <= bytes_to_read);
+ bytes_to_read -= bytes_read;
+ buffer = (void*)(((AP4_Byte*)buffer)+bytes_read);
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Stream::Write
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::Write(const void* buffer, AP4_Size bytes_to_write)
+{
+ // shortcut
+ if (bytes_to_write == 0) return AP4_SUCCESS;
+
+ // write until failure
+ AP4_Size bytes_written;
+ while (bytes_to_write) {
+ AP4_Result result = WritePartial(buffer, bytes_to_write, bytes_written);
+ if (AP4_FAILED(result)) return result;
+ if (bytes_written == 0) return AP4_ERROR_INTERNAL;
+ AP4_ASSERT(bytes_written <= bytes_to_write);
+ bytes_to_write -= bytes_written;
+ buffer = (const void*)(((const AP4_Byte*)buffer)+bytes_written);
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::WriteString
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::WriteString(const char* buffer)
+{
+ AP4_Size string_length = static_cast<AP4_Size>(strlen(buffer));
+
+ // shortcut
+ if ((buffer == NULL) || (string_length == 0)) return AP4_SUCCESS;
+
+ // write the string
+ return Write((const void*)buffer, string_length);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::WriteDouble
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::WriteDouble(double value)
+{
+ unsigned char buffer[8];
+
+ // convert value to bytes
+ AP4_BytesFromDoubleBE(buffer, value);
+
+ // write bytes to the stream
+ return Write((void*)buffer, 8);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::WriteUI64
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::WriteUI64(AP4_UI64 value)
+{
+ unsigned char buffer[8];
+
+ // convert value to bytes
+ AP4_BytesFromUInt64BE(buffer, value);
+
+ // write bytes to the stream
+ return Write((void*)buffer, 8);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::WriteUI32
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::WriteUI32(AP4_UI32 value)
+{
+ unsigned char buffer[4];
+
+ // convert value to bytes
+ AP4_BytesFromUInt32BE(buffer, value);
+
+ // write bytes to the stream
+ return Write((void*)buffer, 4);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::WriteUI24
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::WriteUI24(AP4_UI32 value)
+{
+ unsigned char buffer[3];
+
+ // convert value to bytes
+ AP4_BytesFromUInt24BE(buffer, value);
+
+ // write bytes to the stream
+ return Write((void*)buffer, 3);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::WriteUI16
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::WriteUI16(AP4_UI16 value)
+{
+ unsigned char buffer[2];
+
+ // convert value to bytes
+ AP4_BytesFromUInt16BE(buffer, value);
+
+ // write bytes to the stream
+ return Write((void*)buffer, 2);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::WriteUI08
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::WriteUI08(AP4_UI08 value)
+{
+ return Write((void*)&value, 1);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::ReadUI64
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::ReadUI64(AP4_UI64& value)
+{
+ unsigned char buffer[8];
+
+ // read bytes from the stream
+ AP4_Result result;
+ result = Read((void*)buffer, 8);
+ if (AP4_FAILED(result)) {
+ value = 0;
+ return result;
+ }
+
+ // convert bytes to value
+ value = AP4_BytesToUInt64BE(buffer);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::ReadDouble
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::ReadDouble(double& value)
+{
+ unsigned char buffer[8];
+
+ // read bytes from the stream
+ AP4_Result result;
+ result = Read((void*)buffer, 8);
+ if (AP4_FAILED(result)) {
+ value = 0;
+ return result;
+ }
+
+ // convert bytes to value
+ value = AP4_BytesToDoubleBE(buffer);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::ReadUI32
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::ReadUI32(AP4_UI32& value)
+{
+ unsigned char buffer[4];
+
+ // read bytes from the stream
+ AP4_Result result;
+ result = Read((void*)buffer, 4);
+ if (AP4_FAILED(result)) {
+ value = 0;
+ return result;
+ }
+
+ // convert bytes to value
+ value = AP4_BytesToUInt32BE(buffer);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::ReadUI24
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::ReadUI24(AP4_UI32& value)
+{
+ unsigned char buffer[3];
+
+ // read bytes from the stream
+ AP4_Result result;
+ result = Read((void*)buffer, 3);
+ if (AP4_FAILED(result)) {
+ value = 0;
+ return result;
+ }
+
+ // convert bytes to value
+ value = AP4_BytesToUInt24BE(buffer);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::ReadUI16
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::ReadUI16(AP4_UI16& value)
+{
+ unsigned char buffer[2];
+
+ // read bytes from the stream
+ AP4_Result result;
+ result = Read((void*)buffer, 2);
+ if (AP4_FAILED(result)) {
+ value = 0;
+ return result;
+ }
+
+ // convert bytes to value
+ value = AP4_BytesToUInt16BE(buffer);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::ReadUI08
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::ReadUI08(AP4_UI08& value)
+{
+ unsigned char buffer[1];
+
+ // read bytes from the stream
+ AP4_Result result;
+ result = Read((void*)buffer, 1);
+ if (AP4_FAILED(result)) {
+ value = 0;
+ return result;
+ }
+
+ // convert bytes to value
+ value = buffer[0];
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::ReadString
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::ReadString(char* buffer, AP4_Size size)
+{
+ if (buffer == NULL || size == 0) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+
+ AP4_Size bytes_read = 0;
+ while (bytes_read < size-1) {
+ AP4_Result result;
+ result = Read(&buffer[bytes_read], 1);
+ if (AP4_FAILED(result)) {
+ buffer[bytes_read] = '\0';
+ return result;
+ }
+ if (buffer[bytes_read] == '\0') {
+ // end of string
+ return AP4_SUCCESS;
+ }
+ bytes_read++;
+ }
+
+ // the string was not null terminated, terminate it
+ buffer[size-1] = '\0';
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream::CopyTo
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ByteStream::CopyTo(AP4_ByteStream& stream, AP4_LargeSize size)
+{
+ unsigned char buffer[AP4_BYTE_STREAM_COPY_BUFFER_SIZE];
+ while (size) {
+ AP4_Size bytes_read;
+ AP4_Size bytes_to_read;
+ AP4_Result result;
+
+ // decide how much to read
+ if (size >= sizeof(buffer)) {
+ bytes_to_read = sizeof(buffer);
+ } else {
+ bytes_to_read = (AP4_Size)size;
+ }
+
+ // read up to one buffer full
+ result = ReadPartial(buffer, bytes_to_read, bytes_read);
+ if (AP4_FAILED(result)) return result;
+
+ // copy to destination
+ if (bytes_read != 0) {
+ result = stream.Write(buffer, bytes_read);
+ if (AP4_FAILED(result)) return result;
+ }
+
+ // update the size
+ size -= bytes_read;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SubStream::AP4_SubStream
++---------------------------------------------------------------------*/
+AP4_SubStream::AP4_SubStream(AP4_ByteStream& container,
+ AP4_Position offset,
+ AP4_LargeSize size) :
+ m_Container(container),
+ m_Offset(offset),
+ m_Size(size),
+ m_Position(0),
+ m_ReferenceCount(1)
+{
+ m_Container.AddReference();
+}
+
+/*----------------------------------------------------------------------
+| AP4_SubStream::~AP4_SubStream
++---------------------------------------------------------------------*/
+AP4_SubStream::~AP4_SubStream()
+{
+ m_Container.Release();
+}
+
+/*----------------------------------------------------------------------
+| AP4_SubStream::ReadPartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SubStream::ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read)
+{
+ // default values
+ bytes_read = 0;
+
+ // shortcut
+ if (bytes_to_read == 0) {
+ return AP4_SUCCESS;
+ }
+
+ // clamp to range
+ if (m_Position+bytes_to_read > m_Size) {
+ bytes_to_read = (AP4_Size)(m_Size - m_Position);
+ }
+
+ // check for end of substream
+ if (bytes_to_read == 0) {
+ return AP4_ERROR_EOS;
+ }
+
+ // seek inside container
+ AP4_Result result;
+ result = m_Container.Seek(m_Offset+m_Position);
+ if (AP4_FAILED(result)) {
+ return result;
+ }
+
+ // read from the container
+ result = m_Container.ReadPartial(buffer, bytes_to_read, bytes_read);
+ if (AP4_SUCCEEDED(result)) {
+ m_Position += bytes_read;
+ }
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SubStream::WritePartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SubStream::WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written)
+{
+ // default values
+ bytes_written = 0;
+
+ // shortcut
+ if (bytes_to_write == 0) {
+ return AP4_SUCCESS;
+ }
+
+ // clamp to range
+ if (m_Position+bytes_to_write > m_Size) {
+ bytes_to_write = (AP4_Size)(m_Size - m_Position);
+ }
+
+ // check for en of substream
+ if (bytes_to_write == 0) {
+ return AP4_ERROR_EOS;
+ }
+
+ // seek inside container
+ AP4_Result result;
+ result = m_Container.Seek(m_Offset+m_Position);
+ if (AP4_FAILED(result)) return result;
+
+ // write to container
+ result = m_Container.WritePartial(buffer, bytes_to_write, bytes_written);
+ if (AP4_SUCCEEDED(result)) {
+ m_Position += bytes_written;
+ }
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SubStream::Seek
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SubStream::Seek(AP4_Position position)
+{
+ if (position == m_Position) return AP4_SUCCESS;
+ if (position > m_Size) return AP4_FAILURE;
+ m_Position = position;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SubStream::AddReference
++---------------------------------------------------------------------*/
+void
+AP4_SubStream::AddReference()
+{
+ m_ReferenceCount++;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SubStream::Release
++---------------------------------------------------------------------*/
+void
+AP4_SubStream::Release()
+{
+ if (--m_ReferenceCount == 0) {
+ delete this;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::AP4_MemoryByteStream
++---------------------------------------------------------------------*/
+AP4_MemoryByteStream::AP4_MemoryByteStream(AP4_Size size) :
+ m_BufferIsLocal(true),
+ m_Position(0),
+ m_ReferenceCount(1)
+{
+ m_Buffer = new AP4_DataBuffer(size);
+ AP4_SetMemory(m_Buffer->UseData(), 0, size);
+ m_Buffer->SetDataSize(size);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::AP4_MemoryByteStream
++---------------------------------------------------------------------*/
+AP4_MemoryByteStream::AP4_MemoryByteStream(const AP4_UI08* buffer, AP4_Size size) :
+ m_BufferIsLocal(true),
+ m_Position(0),
+ m_ReferenceCount(1)
+{
+ m_Buffer = new AP4_DataBuffer(buffer, size);
+}
+
+/*----------------------------------------------------------------------
+ | AP4_MemoryByteStream::AP4_MemoryByteStream
+ +---------------------------------------------------------------------*/
+AP4_MemoryByteStream::AP4_MemoryByteStream(AP4_DataBuffer& data_buffer) :
+ m_BufferIsLocal(false),
+ m_Position(0),
+ m_ReferenceCount(1)
+{
+ m_Buffer = &data_buffer;
+}
+
+/*----------------------------------------------------------------------
+ | AP4_MemoryByteStream::~AP4_MemoryByteStream
+ +---------------------------------------------------------------------*/
+AP4_MemoryByteStream::~AP4_MemoryByteStream()
+{
+ if (m_BufferIsLocal) {
+ delete m_Buffer;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::ReadPartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MemoryByteStream::ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read)
+{
+ // default values
+ bytes_read = 0;
+
+ // shortcut
+ if (bytes_to_read == 0) {
+ return AP4_SUCCESS;
+ }
+
+ // clamp to range
+ if (m_Position+bytes_to_read > m_Buffer->GetDataSize()) {
+ bytes_to_read = (AP4_Size)(m_Buffer->GetDataSize() - m_Position);
+ }
+
+ // check for end of stream
+ if (bytes_to_read == 0) {
+ return AP4_ERROR_EOS;
+ }
+
+ // read from the memory
+ AP4_CopyMemory(buffer, m_Buffer->GetData()+m_Position, bytes_to_read);
+ m_Position += bytes_to_read;
+
+ bytes_read = bytes_to_read;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::WritePartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MemoryByteStream::WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written)
+{
+ // default values
+ bytes_written = 0;
+
+ // shortcut
+ if (bytes_to_write == 0) {
+ return AP4_SUCCESS;
+ }
+
+ // check that we don't exceed the max
+ if (m_Position+bytes_to_write > (AP4_Position)AP4_MEMORY_BYTE_STREAM_MAX_SIZE) {
+ return AP4_ERROR_OUT_OF_RANGE;
+ }
+
+ // reserve space in the buffer
+ AP4_Result result = m_Buffer->Reserve((AP4_Size)(m_Position+bytes_to_write));
+ if (AP4_SUCCEEDED(result)) {
+ m_Buffer->SetDataSize((AP4_Size)(m_Position+bytes_to_write));
+ } else {
+ // failed to reserve, most likely caused by a buffer that has
+ // external storage
+ if (m_Position+bytes_to_write > m_Buffer->GetDataSize()) {
+ bytes_to_write = (AP4_Size)(m_Buffer->GetDataSize() - m_Position);
+ }
+ }
+
+ // check for en of stream
+ if (bytes_to_write == 0) {
+ return AP4_ERROR_EOS;
+ }
+
+ // write to memory
+ AP4_CopyMemory((void*)(m_Buffer->UseData()+m_Position), buffer, bytes_to_write);
+ m_Position += bytes_to_write;
+
+ bytes_written = bytes_to_write;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::Seek
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MemoryByteStream::Seek(AP4_Position position)
+{
+ if (position > m_Buffer->GetDataSize()) return AP4_FAILURE;
+ m_Position = position;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::AddReference
++---------------------------------------------------------------------*/
+void
+AP4_MemoryByteStream::AddReference()
+{
+ m_ReferenceCount++;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::Release
++---------------------------------------------------------------------*/
+void
+AP4_MemoryByteStream::Release()
+{
+ if (--m_ReferenceCount == 0) {
+ delete this;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream::AP4_BufferedInputStream
++---------------------------------------------------------------------*/
+AP4_BufferedInputStream::AP4_BufferedInputStream(AP4_ByteStream& source,
+ AP4_Size buffer_size,
+ AP4_Size seek_as_read_threshold) :
+ m_Buffer(buffer_size),
+ m_BufferPosition(0),
+ m_Source(source),
+ m_SourcePosition(0),
+ m_SeekAsReadThreshold(seek_as_read_threshold),
+ m_ReferenceCount(1)
+{
+ source.AddReference();
+}
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream::Refill
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_BufferedInputStream::Refill()
+{
+ m_BufferPosition = 0;
+ AP4_Size bytes_read = 0;
+ AP4_Result result = m_Source.ReadPartial(m_Buffer.UseData(),
+ m_Buffer.GetBufferSize(),
+ bytes_read);
+ if (AP4_FAILED(result)) {
+ m_Buffer.SetDataSize(0);
+ return result;
+ }
+ assert(bytes_read);
+ m_Buffer.SetDataSize(bytes_read);
+ m_SourcePosition += bytes_read;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream::ReadPartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_BufferedInputStream::ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read)
+{
+ // check for shortcut
+ if (bytes_to_read == 0) {
+ bytes_read = 0;
+ return AP4_SUCCESS;
+ }
+
+ // compute how much data is available in the buffer
+ assert(m_BufferPosition <= m_Buffer.GetDataSize());
+ AP4_Size available = m_Buffer.GetDataSize()-m_BufferPosition;
+
+ // refill the buffer if it is empty
+ if (available == 0) {
+ AP4_Result result = Refill();
+ if (AP4_FAILED(result)) {
+ bytes_read = 0;
+ return result;
+ }
+ assert(m_BufferPosition == 0);
+ assert(m_Buffer.GetDataSize() != 0);
+ available = m_Buffer.GetDataSize()-m_BufferPosition;
+ }
+
+ // clamp the number of bytes to read to what's available
+ if (bytes_to_read > available) bytes_to_read = available;
+ bytes_read = bytes_to_read;
+
+ // copy the buffered data
+ AP4_CopyMemory(buffer, m_Buffer.GetData()+m_BufferPosition, bytes_to_read);
+ m_BufferPosition += bytes_to_read;
+ assert(m_BufferPosition <= m_Buffer.GetDataSize());
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream::WritePartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_BufferedInputStream::WritePartial(const void* /*buffer*/,
+ AP4_Size /*bytes_to_write*/,
+ AP4_Size& /*bytes_written*/)
+{
+ return AP4_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream::Seek
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_BufferedInputStream::Seek(AP4_Position position)
+{
+ assert(m_SourcePosition >= m_Buffer.GetDataSize());
+ assert(m_BufferPosition <= m_Buffer.GetDataSize());
+ if (position < m_SourcePosition-m_Buffer.GetDataSize() ||
+ position > m_SourcePosition) {
+ // out of buffer
+ m_BufferPosition = 0;
+ m_Buffer.SetDataSize(0);
+
+ // seek in the source
+ if (position > m_SourcePosition && (position-m_SourcePosition <= m_SeekAsReadThreshold)) {
+ char* discard = new char[4096];
+ AP4_Size to_skip = (AP4_Size)(position-m_SourcePosition);
+ while (to_skip) {
+ AP4_Size chunk = 4096;
+ if (chunk > to_skip) chunk = to_skip;
+ AP4_Result result = m_Source.Read(discard, chunk);
+ if (AP4_FAILED(result)) {
+ delete[] discard;
+ return result;
+ }
+ m_SourcePosition += chunk;
+ to_skip -= chunk;
+ }
+ delete[] discard;
+ return AP4_SUCCESS;
+ } else {
+ m_SourcePosition = position;
+ return m_Source.Seek(position);
+ }
+ }
+
+ // compute the buffer position
+ m_BufferPosition = (AP4_Size)(position-(m_SourcePosition-m_Buffer.GetDataSize()));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream::Tell
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_BufferedInputStream::Tell(AP4_Position& position)
+{
+ assert(m_SourcePosition >= m_Buffer.GetDataSize());
+ assert(m_BufferPosition <= m_Buffer.GetDataSize());
+ position = m_SourcePosition-m_Buffer.GetDataSize()+m_BufferPosition;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream::AddReference
++---------------------------------------------------------------------*/
+void
+AP4_BufferedInputStream::AddReference()
+{
+ m_ReferenceCount++;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream::Release
++---------------------------------------------------------------------*/
+void
+AP4_BufferedInputStream::Release()
+{
+ if (--m_ReferenceCount == 0) {
+ delete this;
+ }
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ByteStream.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ByteStream.h new file mode 100644 index 000000000..3eaf2d803 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ByteStream.h @@ -0,0 +1,202 @@ +/*****************************************************************
+|
+| AP4 - ByteStream Interface
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_BYTE_STREAM_H_
+#define _AP4_BYTE_STREAM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4Interfaces.h"
+#include "Ap4Results.h"
+#include "Ap4DataBuffer.h"
+
+/*----------------------------------------------------------------------
+| AP4_ByteStream
++---------------------------------------------------------------------*/
+class AP4_ByteStream : public AP4_Referenceable
+{
+ public:
+ // methods
+ virtual AP4_Result ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read) = 0;
+ AP4_Result Read(void* buffer, AP4_Size bytes_to_read);
+ AP4_Result ReadDouble(double& value);
+ AP4_Result ReadUI64(AP4_UI64& value);
+ AP4_Result ReadUI32(AP4_UI32& value);
+ AP4_Result ReadUI24(AP4_UI32& value);
+ AP4_Result ReadUI16(AP4_UI16& value);
+ AP4_Result ReadUI08(AP4_UI08& value);
+ AP4_Result ReadString(char* buffer, AP4_Size size);
+ virtual AP4_Result WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written) = 0;
+ AP4_Result Write(const void* buffer, AP4_Size bytes_to_write);
+ AP4_Result WriteString(const char* string_buffer);
+ AP4_Result WriteDouble(double value);
+ AP4_Result WriteUI64(AP4_UI64 value);
+ AP4_Result WriteUI32(AP4_UI32 value);
+ AP4_Result WriteUI24(AP4_UI32 value);
+ AP4_Result WriteUI16(AP4_UI16 value);
+ AP4_Result WriteUI08(AP4_UI08 value);
+ virtual AP4_Result Seek(AP4_Position position) = 0;
+ virtual AP4_Result Tell(AP4_Position& position) = 0;
+ virtual AP4_Result GetSize(AP4_LargeSize& size) = 0;
+ virtual AP4_Result CopyTo(AP4_ByteStream& stream, AP4_LargeSize size);
+ virtual AP4_Result Flush() { return AP4_SUCCESS; }
+};
+
+/*----------------------------------------------------------------------
+| AP4_SubStream
++---------------------------------------------------------------------*/
+class AP4_SubStream : public AP4_ByteStream
+{
+ public:
+ AP4_SubStream(AP4_ByteStream& container,
+ AP4_Position position,
+ AP4_LargeSize size);
+
+ // AP4_ByteStream methods
+ AP4_Result ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read);
+ AP4_Result WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written);
+ AP4_Result Seek(AP4_Position position);
+ AP4_Result Tell(AP4_Position& position) {
+ position = m_Position;
+ return AP4_SUCCESS;
+ }
+ AP4_Result GetSize(AP4_LargeSize& size) {
+ size = m_Size;
+ return AP4_SUCCESS;
+ }
+
+ // AP4_Referenceable methods
+ void AddReference();
+ void Release();
+
+ protected:
+ virtual ~AP4_SubStream();
+
+ private:
+ AP4_ByteStream& m_Container;
+ AP4_Position m_Offset;
+ AP4_LargeSize m_Size;
+ AP4_Position m_Position;
+ AP4_Cardinal m_ReferenceCount;
+};
+
+/*----------------------------------------------------------------------
+| AP4_MemoryByteStream
++---------------------------------------------------------------------*/
+class AP4_MemoryByteStream : public AP4_ByteStream
+{
+public:
+ AP4_MemoryByteStream(AP4_Size size = 0); // filled with zeros
+ AP4_MemoryByteStream(const AP4_UI08* buffer, AP4_Size size);
+ AP4_MemoryByteStream(AP4_DataBuffer& data_buffer); // data is read/written from/to supplied buffer
+
+ // AP4_ByteStream methods
+ AP4_Result ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read);
+ AP4_Result WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written);
+ AP4_Result Seek(AP4_Position position);
+ AP4_Result Tell(AP4_Position& position) {
+ position = m_Position;
+ return AP4_SUCCESS;
+ }
+ AP4_Result GetSize(AP4_LargeSize& size) {
+ size = m_Buffer->GetDataSize();
+ return AP4_SUCCESS;
+ }
+
+ // AP4_Referenceable methods
+ void AddReference();
+ void Release();
+
+ // methods
+ const AP4_UI08* GetData() { return m_Buffer->GetData(); }
+ AP4_UI08* UseData() { return m_Buffer->UseData(); }
+ AP4_Size GetDataSize() { return m_Buffer->GetDataSize(); }
+
+protected:
+ virtual ~AP4_MemoryByteStream();
+
+private:
+ AP4_DataBuffer* m_Buffer;
+ bool m_BufferIsLocal;
+ AP4_Position m_Position;
+ AP4_Cardinal m_ReferenceCount;
+};
+
+/*----------------------------------------------------------------------
+| AP4_BufferedInputStream
++---------------------------------------------------------------------*/
+class AP4_BufferedInputStream : public AP4_ByteStream
+{
+public:
+ AP4_BufferedInputStream(AP4_ByteStream& source,
+ AP4_Size buffer_size=4096,
+ AP4_Size seek_as_read_threshold=1024*128);
+
+ // AP4_ByteStream methods
+ AP4_Result ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read);
+ AP4_Result WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written);
+ AP4_Result Seek(AP4_Position position);
+ AP4_Result Tell(AP4_Position& position);
+ AP4_Result GetSize(AP4_LargeSize& size) { return m_Source.GetSize(size); }
+
+ // AP4_Referenceable methods
+ void AddReference();
+ void Release();
+
+protected:
+ ~AP4_BufferedInputStream() { m_Source.Release(); }
+ AP4_Result Refill();
+
+private:
+ AP4_DataBuffer m_Buffer;
+ AP4_Size m_BufferPosition;
+ AP4_ByteStream& m_Source;
+ AP4_Position m_SourcePosition;
+ AP4_Size m_SeekAsReadThreshold;
+ AP4_Cardinal m_ReferenceCount;
+};
+
+#endif // _AP4_BYTE_STREAM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ChplAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ChplAtom.cpp new file mode 100644 index 000000000..2c5c195a3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ChplAtom.cpp @@ -0,0 +1,71 @@ +/*****************************************************************
+|
+| AP4 - chpl Atom
+|
+| Copyright 2002 Gilles Boccon-Gibod & Julien Boeuf
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+
+#include "Ap4ChplAtom.h"
+
+/*----------------------------------------------------------------------
+| AP4_ChplAtom::AP4_ChplAtom
++---------------------------------------------------------------------*/
+
+AP4_ChplAtom::AP4_ChplAtom(AP4_UI32 size,
+ AP4_ByteStream& stream)
+ : AP4_Atom(AP4_ATOM_TYPE_CHPL, size)
+{
+ size -= AP4_FULL_ATOM_HEADER_SIZE;
+
+ stream.ReadUI32(m_Reserved);
+
+ AP4_UI08 cnt = 0;
+ stream.ReadUI08(cnt);
+
+ size -= 5;
+
+ while(size > 0 && cnt-- > 0)
+ {
+ AP4_Chapter chapter;
+
+ // time
+ stream.ReadUI64(chapter.Time);
+
+ // name
+ AP4_UI08 len = 0;
+ char buff[256];
+ stream.ReadUI08(len);
+ stream.Read(buff, len);
+ buff[len] = 0;
+ chapter.Name = buff;
+
+ m_Chapters.Append(chapter);
+
+ size -= 8+1+len;
+ }
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ChplAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ChplAtom.h new file mode 100644 index 000000000..d1fa4327b --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ChplAtom.h @@ -0,0 +1,62 @@ +/*****************************************************************
+|
+| AP4 - chpl Atom
+|
+| Copyright 2002 Gilles Boccon-Gibod & Julien Boeuf
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_CHPL_ATOM_H_
+#define _AP4_CHPL_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+#include "Ap4Types.h"
+#include "Ap4Array.h"
+#include "Ap4DataBuffer.h"
+
+/*----------------------------------------------------------------------
+| AP4_ChplAtom
++---------------------------------------------------------------------*/
+class AP4_ChplAtom : public AP4_Atom
+{
+public:
+ AP4_ChplAtom(AP4_UI32 size,
+ AP4_ByteStream& stream);
+
+ AP4_Result WriteFields(AP4_ByteStream& stream) { return AP4_FAILURE; }
+
+ struct AP4_Chapter {AP4_UI64 Time; AP4_String Name;};
+
+ AP4_Array<AP4_Chapter>& GetChapters() { return m_Chapters; }
+
+private:
+
+ // members
+ AP4_UI32 m_Reserved;
+ AP4_Array<AP4_Chapter> m_Chapters;
+};
+
+#endif // _AP4_CHPL_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CmvdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CmvdAtom.cpp new file mode 100644 index 000000000..8b4760524 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CmvdAtom.cpp @@ -0,0 +1,73 @@ +/*****************************************************************
+|
+| AP4 - cmvd Atoms
+|
+| Copyright 2002 Gilles Boccon-Gibod
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4.h"
+#include "Ap4CmvdAtom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4ContainerAtom.h"
+
+AP4_CmvdAtom* +AP4_CmvdAtom::Create(AP4_Size size, AP4_ByteStream& stream, AP4_AtomFactory& atom_factory) +{ + return new AP4_CmvdAtom(size, stream, atom_factory); +}
+
+/*----------------------------------------------------------------------
+| AP4_CmvdAtom::AP4_CmvdAtom
++---------------------------------------------------------------------*/
+AP4_CmvdAtom::AP4_CmvdAtom(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_ContainerAtom(AP4_ATOM_TYPE_CMVD)
+{
+ size -= AP4_ATOM_HEADER_SIZE;
+
+ stream.ReadUI32(m_MovieResourceSize);
+
+ size -= 4;
+
+ m_Data.SetDataSize(size);
+ stream.Read(m_Data.UseData(), size);
+
+/*
+ // read children
+ AP4_Size bytes_available = size-AP4_FULL_ATOM_HEADER_SIZE-4;
+ while (entry_count--) {
+ AP4_Atom* atom;
+ while (AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(stream,
+ bytes_available,
+ atom,
+ this))) {
+ m_Children.Add(atom);
+ }
+ }
+*/
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CmvdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CmvdAtom.h new file mode 100644 index 000000000..51e2ca843 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CmvdAtom.h @@ -0,0 +1,67 @@ +/*****************************************************************
+|
+| AP4 - cmvd Atoms
+|
+| Copyright 2002 Gilles Boccon-Gibod
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_CMVD_ATOM_H_
+#define _AP4_CMVD_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4.h"
+#include "Ap4ByteStream.h"
+#include "Ap4Array.h"
+#include "Ap4Atom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4ContainerAtom.h"
+#include "Ap4DataBuffer.h"
+
+/*----------------------------------------------------------------------
+| AP4_CmvdAtom
++---------------------------------------------------------------------*/
+class AP4_CmvdAtom : public AP4_ContainerAtom
+{
+public:
+ // class methods + static AP4_CmvdAtom* Create(AP4_Size size, AP4_ByteStream& stream, AP4_AtomFactory& atom_factory); +
+ // methods
+ AP4_CmvdAtom(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory);
+
+ virtual AP4_Result WriteFields(AP4_ByteStream& stream) { return AP4_FAILURE; }
+
+ AP4_UI32 GetMovieResourceSize() const { return m_MovieResourceSize; }
+ const AP4_DataBuffer& GetDataBuffer() { return m_Data; }
+
+private:
+ AP4_UI32 m_MovieResourceSize;
+ AP4_DataBuffer m_Data;
+};
+
+#endif // _AP4_CMVD_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Co64Atom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Co64Atom.cpp new file mode 100644 index 000000000..3dea98337 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Co64Atom.cpp @@ -0,0 +1,178 @@ +/***************************************************************** +| +| AP4 - co64 Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Co64Atom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Co64Atom) + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::Create ++---------------------------------------------------------------------*/ +AP4_Co64Atom* +AP4_Co64Atom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_Co64Atom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::AP4_Co64Atom ++---------------------------------------------------------------------*/ +AP4_Co64Atom::AP4_Co64Atom(AP4_UI64* entries, AP4_UI32 entry_count) : +AP4_Atom(AP4_ATOM_TYPE_CO64, + AP4_FULL_ATOM_HEADER_SIZE+4+entry_count*8, + 0, 0), + m_Entries(new AP4_UI64[entry_count]), + m_EntryCount(entry_count) +{ + AP4_CopyMemory(m_Entries, entries, m_EntryCount*8); +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::AP4_Co64Atom ++---------------------------------------------------------------------*/ +AP4_Co64Atom::AP4_Co64Atom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_CO64, size, version, flags) +{ + stream.ReadUI32(m_EntryCount); + if (m_EntryCount > (size-AP4_FULL_ATOM_HEADER_SIZE-4)/8) { + m_EntryCount = (size-AP4_FULL_ATOM_HEADER_SIZE-4)/8; + } + m_Entries = new AP4_UI64[m_EntryCount]; + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + stream.ReadUI64(m_Entries[i]); + } +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::~AP4_Co64Atom ++---------------------------------------------------------------------*/ +AP4_Co64Atom::~AP4_Co64Atom() +{ + delete[] m_Entries; +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::GetChunkOffset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Co64Atom::GetChunkOffset(AP4_Ordinal chunk, AP4_UI64& chunk_offset) +{ + // check the bounds + if (chunk > m_EntryCount || chunk == 0) { + return AP4_ERROR_OUT_OF_RANGE; + } + + // get the chunk offset + chunk_offset = m_Entries[chunk - 1]; // m_Entries is zero index based + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::SetChunkOffset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Co64Atom::SetChunkOffset(AP4_Ordinal chunk, AP4_UI64 chunk_offset) +{ + // check the bounds + if (chunk > m_EntryCount || chunk == 0) { + return AP4_ERROR_OUT_OF_RANGE; + } + + // get the chunk offset + m_Entries[chunk - 1] = chunk_offset; // m_Entries is zero index based + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::AdjustChunkOffsets ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Co64Atom::AdjustChunkOffsets(AP4_SI64 delta) +{ + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + m_Entries[i] += delta; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Co64Atom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // entry count + result = stream.WriteUI32(m_EntryCount); + if (AP4_FAILED(result)) return result; + + // entries + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + result = stream.WriteUI64(m_Entries[i]); + if (AP4_FAILED(result)) return result; + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_Co64Atom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Co64Atom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("entry_count", m_EntryCount); + if (inspector.GetVerbosity() >= 1) { + char header[32]; + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + AP4_FormatString(header, sizeof(header), "entry %8d", i); + inspector.AddField(header, m_Entries[i]); + } + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Co64Atom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Co64Atom.h new file mode 100644 index 000000000..bdfeb4736 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Co64Atom.h @@ -0,0 +1,72 @@ +/***************************************************************** +| +| AP4 - co64 Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_CO64_ATOM_H_ +#define _AP4_CO64_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_Co64Atom ++---------------------------------------------------------------------*/ +class AP4_Co64Atom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_Co64Atom, AP4_Atom) + + // class methods + static AP4_Co64Atom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_Co64Atom(AP4_UI64* offsets, AP4_UI32 offset_count); + ~AP4_Co64Atom(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + AP4_Cardinal GetChunkCount() { return m_EntryCount; } + AP4_UI64* GetChunkOffsets() { return m_Entries; } + AP4_Result GetChunkOffset(AP4_Ordinal chunk, AP4_UI64& chunk_offset); + AP4_Result SetChunkOffset(AP4_Ordinal chunk, AP4_UI64 chunk_offset); + AP4_Result AdjustChunkOffsets(AP4_SI64 delta); + +private: + // methods + AP4_Co64Atom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI64* m_Entries; + AP4_UI32 m_EntryCount; +}; + +#endif // _AP4_CO64_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Command.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Command.cpp new file mode 100644 index 000000000..1dc6958f5 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Command.cpp @@ -0,0 +1,82 @@ +/***************************************************************** +| +| AP4 - Commands +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Command.h" +#include "Ap4Utils.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Command) + +/*---------------------------------------------------------------------- +| AP4_Command::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Command::Inspect(AP4_AtomInspector& inspector) +{ + char name[6]; + AP4_FormatString(name, sizeof(name), "[Command:%02x]", m_ClassId); + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(), + m_PayloadSize); + inspector.StartElement(name, info); + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_UnknownCommand::AP4_UnknownCommand ++---------------------------------------------------------------------*/ +AP4_UnknownCommand::AP4_UnknownCommand(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Command(tag, header_size, payload_size) +{ + m_Data.SetDataSize(payload_size); + stream.Read(m_Data.UseData(), payload_size); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownCommand::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_UnknownCommand::WriteFields(AP4_ByteStream& stream) +{ + // write the payload + stream.Write(m_Data.GetData(), m_Data.GetDataSize()); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Command.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Command.h new file mode 100644 index 000000000..50cf8d736 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Command.h @@ -0,0 +1,89 @@ +/***************************************************************** +| +| AP4 - Commands +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_COMMAND_H_ +#define _AP4_COMMAND_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Expandable.h" +#include "Ap4DynamicCast.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_UPDATE = 0x01; +const AP4_UI08 AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_REMOVE = 0x02; +const AP4_UI08 AP4_COMMAND_TAG_ES_DESCRIPTOR_UPDATE = 0x03; +const AP4_UI08 AP4_COMMAND_TAG_ES_DESCRIPTOR_REMOVE = 0x04; +const AP4_UI08 AP4_COMMAND_TAG_IPMP_DESCRIPTOR_UPDATE = 0x05; +const AP4_UI08 AP4_COMMAND_TAG_IPMP_DESCRIPTOR_REMOVE = 0x06; +const AP4_UI08 AP4_COMMAND_TAG_ES_DESCRIPTOR_REMOVE_REF = 0x07; +const AP4_UI08 AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_EXECUTE = 0x08; + +/*---------------------------------------------------------------------- +| AP4_Command ++---------------------------------------------------------------------*/ +class AP4_Command : public AP4_Expandable +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST(AP4_Command) + + // constructor + AP4_Command(AP4_UI08 tag, AP4_Size header_size, AP4_Size payload_size) : + AP4_Expandable(tag, CLASS_ID_SIZE_08, header_size, payload_size) {} + + // AP4_Exandable methods + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // methods + AP4_UI08 GetTag() { return (AP4_UI08)m_ClassId; } +}; + +/*---------------------------------------------------------------------- +| AP4_UnknownCommand ++---------------------------------------------------------------------*/ +class AP4_UnknownCommand : public AP4_Command +{ +public: + // contrusctor + AP4_UnknownCommand(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size); + + // AP4_Expandable methods + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // members + AP4_DataBuffer m_Data; +}; + +#endif // _AP4_COMMAND_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CommandFactory.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CommandFactory.cpp new file mode 100644 index 000000000..f41312bda --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CommandFactory.cpp @@ -0,0 +1,93 @@ +/***************************************************************** +| +| AP4 - Command Factory +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4CommandFactory.h" +#include "Ap4ObjectDescriptor.h" +#include "Ap4Command.h" +#include "Ap4ByteStream.h" + +/*---------------------------------------------------------------------- +| AP4_CommandFactory::CreateCommandFromStream ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CommandFactory::CreateCommandFromStream(AP4_ByteStream& stream, + AP4_Command*& command) +{ + AP4_Result result; + + // NULL by default + command = NULL; + + // remember current stream offset + AP4_Position offset; + stream.Tell(offset); + + // read descriptor tag + unsigned char tag; + result = stream.ReadUI08(tag); + if (AP4_FAILED(result)) { + stream.Seek(offset); + return result; + } + + // read descriptor size + unsigned long payload_size = 0; + unsigned int header_size = 1; + unsigned int max = 4; + unsigned char ext = 0; + do { + header_size++; + result = stream.ReadUI08(ext); + if (AP4_FAILED(result)) { + stream.Seek(offset); + return result; + } + payload_size = (payload_size<<7) + (ext&0x7F); + } while (--max && (ext&0x80)); + + // create the command + switch (tag) { + case AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_UPDATE: + case AP4_COMMAND_TAG_IPMP_DESCRIPTOR_UPDATE: + command = new AP4_DescriptorUpdateCommand(stream, tag, header_size, payload_size); + break; + + default: + command = new AP4_UnknownCommand(stream, tag, header_size, payload_size); + break; + } + + // skip to the end of the descriptor + stream.Seek(offset+header_size+payload_size); + + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CommandFactory.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CommandFactory.h new file mode 100644 index 000000000..133b35020 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CommandFactory.h @@ -0,0 +1,54 @@ +/***************************************************************** +| +| AP4 - Command Factory +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_COMMAND_FACTORY_H_ +#define _AP4_COMMAND_FACTORY_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Command.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_CommandFactory ++---------------------------------------------------------------------*/ +class AP4_CommandFactory +{ + public: + // class methods + static AP4_Result CreateCommandFromStream(AP4_ByteStream& stream, + AP4_Command*& command); +}; + +#endif // _AP4_COMMAND_FACTORY_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Constants.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Constants.h new file mode 100644 index 000000000..3d750dd30 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Constants.h @@ -0,0 +1,39 @@ +/***************************************************************** +| +| AP4 - Shared Constants +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_CONSTANTS_H_ +#define _AP4_CONSTANTS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#ifndef NULL +#define NULL 0 +#endif + +#endif // _AP4_CONSTANTS_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ContainerAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ContainerAtom.cpp new file mode 100644 index 000000000..deee12653 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ContainerAtom.cpp @@ -0,0 +1,268 @@ +/***************************************************************** +| +| AP4 - Container Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Utils.h" +#include "Ap4ContainerAtom.h" +#include "Ap4AtomFactory.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_ContainerAtom) + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::AP4_ContainerAtom ++---------------------------------------------------------------------*/ +AP4_ContainerAtom* +AP4_ContainerAtom::Create(Type type, + AP4_UI64 size, + bool is_full, + bool force_64, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) +{ + if (is_full) { + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + + // special case for 'meta' atoms, because Apple sometimes creates them as + // regular (non-full) atoms. This is bogus, but we can try to detect it + if (type == AP4_ATOM_TYPE_META) { + AP4_UI32 phantom_size = (version<<24)|flags; + if (phantom_size >= 8 && size >= 16) { + // version+flags looks like a size. read the next 4 bytes just + // to be sure it is a hdlr atom + AP4_UI32 peek; + if (AP4_FAILED(stream.ReadUI32(peek))) return NULL; + if (peek == AP4_ATOM_TYPE_HDLR) { + // rewind the stream by 8 bytes + AP4_Position position; + stream.Tell(position); + stream.Seek(position-8); + + // create a non-full container + return new AP4_ContainerAtom(type, size, force_64, stream, atom_factory); + } + } + } + + return new AP4_ContainerAtom(type, size, force_64, version, flags, stream, atom_factory); + } else { + return new AP4_ContainerAtom(type, size, force_64, stream, atom_factory); + } +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::AP4_ContainerAtom ++---------------------------------------------------------------------*/ +AP4_ContainerAtom::AP4_ContainerAtom(Type type) : + AP4_Atom(type, AP4_ATOM_HEADER_SIZE) +{ +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::AP4_ContainerAtom ++---------------------------------------------------------------------*/ +AP4_ContainerAtom::AP4_ContainerAtom(Type type, AP4_UI32 version, AP4_UI32 flags) : + AP4_Atom(type, AP4_FULL_ATOM_HEADER_SIZE, version, flags) +{ +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::AP4_ContainerAtom ++---------------------------------------------------------------------*/ +AP4_ContainerAtom::AP4_ContainerAtom(Type type, AP4_UI64 size, bool force_64) : + AP4_Atom(type, size, force_64) +{ +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::AP4_ContainerAtom ++---------------------------------------------------------------------*/ +AP4_ContainerAtom::AP4_ContainerAtom(Type type, + AP4_UI64 size, + bool force_64, + AP4_UI32 version, + AP4_UI32 flags) : + AP4_Atom(type, size, force_64, version, flags) +{ +} + + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::AP4_ContainerAtom ++---------------------------------------------------------------------*/ +AP4_ContainerAtom::AP4_ContainerAtom(Type type, + AP4_UI64 size, + bool force_64, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_Atom(type, size, force_64) +{ + ReadChildren(atom_factory, stream, size-GetHeaderSize()); +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::AP4_ContainerAtom ++---------------------------------------------------------------------*/ +AP4_ContainerAtom::AP4_ContainerAtom(Type type, + AP4_UI64 size, + bool force_64, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_Atom(type, size, force_64, version, flags) +{ + ReadChildren(atom_factory, stream, size-GetHeaderSize()); +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::Clone ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_ContainerAtom::Clone() +{ + AP4_ContainerAtom* clone; + if (m_IsFull) { + clone = new AP4_ContainerAtom(m_Type, m_Version, m_Flags); + } else { + clone = new AP4_ContainerAtom(m_Type); + } + + AP4_List<AP4_Atom>::Item* child_item = m_Children.FirstItem(); + while (child_item) { + AP4_Atom* child_clone = child_item->GetData()->Clone(); + if (child_clone) clone->AddChild(child_clone); + child_item = child_item->GetNext(); + } + + return clone; +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::ReadChildren ++---------------------------------------------------------------------*/ +void +AP4_ContainerAtom::ReadChildren(AP4_AtomFactory& atom_factory, + AP4_ByteStream& stream, + AP4_UI64 size) +{ + AP4_Atom* atom; + AP4_LargeSize bytes_available = size; + + // save and switch the factory's context + atom_factory.PushContext(m_Type); + + while (AP4_SUCCEEDED( + atom_factory.CreateAtomFromStream(stream, bytes_available, atom))) { + atom->SetParent(this); + m_Children.Add(atom); + } + + // restore the saved context + atom_factory.PopContext(); +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ContainerAtom::InspectFields(AP4_AtomInspector& inspector) +{ + return InspectChildren(inspector); +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::InspectChildren ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ContainerAtom::InspectChildren(AP4_AtomInspector& inspector) +{ + // inspect children + m_Children.Apply(AP4_AtomListInspector(inspector)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ContainerAtom::WriteFields(AP4_ByteStream& stream) +{ + // write all children + return m_Children.Apply(AP4_AtomListWriter(stream)); +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::OnChildChanged ++---------------------------------------------------------------------*/ +void +AP4_ContainerAtom::OnChildChanged(AP4_Atom*) +{ + // remcompute our size + AP4_UI64 size = GetHeaderSize(); + m_Children.Apply(AP4_AtomSizeAdder(size)); + SetSize(size); + + // update our parent + if (m_Parent) m_Parent->OnChildChanged(this); +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::OnChildAdded ++---------------------------------------------------------------------*/ +void +AP4_ContainerAtom::OnChildAdded(AP4_Atom* child) +{ + // update our size + SetSize(GetSize()+child->GetSize()); + + // update our parent + if (m_Parent) m_Parent->OnChildChanged(this); +} + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom::OnChildRemoved ++---------------------------------------------------------------------*/ +void +AP4_ContainerAtom::OnChildRemoved(AP4_Atom* child) +{ + // update our size + SetSize(GetSize()-child->GetSize()); + + // update our parent + if (m_Parent) m_Parent->OnChildChanged(this); +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ContainerAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ContainerAtom.h new file mode 100644 index 000000000..b19e18637 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ContainerAtom.h @@ -0,0 +1,98 @@ +/***************************************************************** +| +| AP4 - Container Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_CONTAINER_ATOM_H_ +#define _AP4_CONTAINER_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_AtomFactory; + +/*---------------------------------------------------------------------- +| AP4_ContainerAtom ++---------------------------------------------------------------------*/ +class AP4_ContainerAtom : public AP4_Atom, public AP4_AtomParent +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_ContainerAtom, AP4_Atom, AP4_AtomParent) + + // class methods + static AP4_ContainerAtom* Create(Type type, + AP4_UI64 size, + bool is_full, + bool force_64, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + explicit AP4_ContainerAtom(Type type); + explicit AP4_ContainerAtom(Type type, AP4_UI32 version, AP4_UI32 flags); + explicit AP4_ContainerAtom(Type type, AP4_UI64 size, bool force_64); + explicit AP4_ContainerAtom(Type type, AP4_UI64 size, bool force_64, AP4_UI32 version, AP4_UI32 flags); + AP4_List<AP4_Atom>& GetChildren() { return m_Children; } + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result InspectChildren(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Atom* Clone(); + + // AP4_AtomParent methods + virtual void OnChildChanged(AP4_Atom* child); + virtual void OnChildAdded(AP4_Atom* child); + virtual void OnChildRemoved(AP4_Atom* child); + +protected: + // constructors + AP4_ContainerAtom(Type type, + AP4_UI64 size, + bool force_64, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + AP4_ContainerAtom(Type type, + AP4_UI64 size, + bool force_64, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + void ReadChildren(AP4_AtomFactory& atom_factory, + AP4_ByteStream& stream, + AP4_UI64 size); +}; + +#endif // _AP4_CONTAINER_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CttsAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CttsAtom.cpp new file mode 100644 index 000000000..fc431825a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CttsAtom.cpp @@ -0,0 +1,211 @@ +/*****************************************************************
+|
+| AP4 - ctts Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4CttsAtom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4Utils.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_CttsAtom)
+
+/*----------------------------------------------------------------------
+| AP4_CttsAtom::Create
++---------------------------------------------------------------------*/
+AP4_CttsAtom*
+AP4_CttsAtom::Create(AP4_UI32 size, AP4_ByteStream& stream)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version != 0) return NULL;
+ return new AP4_CttsAtom(size, version, flags, stream);
+}
+
+/*----------------------------------------------------------------------
+| AP4_CttsAtom::AP4_CttsAtom
++---------------------------------------------------------------------*/
+AP4_CttsAtom::AP4_CttsAtom() :
+ AP4_Atom(AP4_ATOM_TYPE_CTTS, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0)
+{
+ m_LookupCache.sample = 0;
+ m_LookupCache.entry_index = 0;
+}
+
+/*----------------------------------------------------------------------
+| AP4_CttsAtom::AP4_CttsAtom
++---------------------------------------------------------------------*/
+AP4_CttsAtom::AP4_CttsAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream) :
+ AP4_Atom(AP4_ATOM_TYPE_CTTS, size, version, flags)
+{
+ m_LookupCache.sample = 0;
+ m_LookupCache.entry_index = 0;
+
+ AP4_UI32 entry_count;
+ stream.ReadUI32(entry_count);
+ m_Entries.SetItemCount(entry_count);
+ unsigned char* buffer = new unsigned char[entry_count*8];
+ AP4_Result result = stream.Read(buffer, entry_count*8);
+ if (AP4_FAILED(result)) {
+ delete[] buffer;
+ return;
+ }
+ //bool use_quicktime_format = false;
+ //AP4_SI32 quicktime_min_offset = 0;
+ for (unsigned i=0; i<entry_count; i++) {
+ m_Entries[i].m_SampleCount = AP4_BytesToUInt32BE(&buffer[i*8 ]);
+ AP4_UI32 offset = AP4_BytesToUInt32BE(&buffer[i*8+4]);
+ //if (offset & 0x80000000) {
+ // use_quicktime_format = true;
+ // AP4_SI32 noffset = (AP4_SI32)offset;
+ // if (noffset < quicktime_min_offset) quicktime_min_offset = noffset;
+ //}
+ m_Entries[i].m_SampleOffset = offset;
+ }
+ delete[] buffer;
+
+ // in the quicktime format, the offsets can be positive or negative, so
+ // we need to adjust for them here
+ //if (use_quicktime_format) {
+ // for (unsigned i=0; i<entry_count; i++) {
+ // m_Entries[i].m_SampleOffset -= quicktime_min_offset;
+ // }
+ //}
+}
+
+/*----------------------------------------------------------------------
+| AP4_CttsAtom::AddEntry
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_CttsAtom::AddEntry(AP4_UI32 count, AP4_UI32 cts_offset)
+{
+ m_Entries.Append(AP4_CttsTableEntry(count, cts_offset));
+ m_Size32 += 8;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_CttsAtom::GetCtsOffset
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_CttsAtom::GetCtsOffset(AP4_Ordinal sample, AP4_UI32& cts_offset)
+{
+ // default value
+ cts_offset = 0;
+
+ // sample indexes start at 1
+ if (sample == 0) return AP4_ERROR_OUT_OF_RANGE;
+
+ // check the lookup cache
+ AP4_Ordinal lookup_start = 0;
+ AP4_Ordinal sample_start = 0;
+ if (sample >= m_LookupCache.sample) {
+ // start from the cached entry
+ lookup_start = m_LookupCache.entry_index;
+ sample_start = m_LookupCache.sample;
+ }
+
+ for (AP4_Ordinal i = lookup_start; i < m_Entries.ItemCount(); i++) {
+ AP4_CttsTableEntry& entry = m_Entries[i];
+
+ // check if we have reached the sample
+ if (sample <= sample_start+entry.m_SampleCount) {
+ // we are within the sample range for the current entry
+ cts_offset = entry.m_SampleOffset;
+
+ // update the lookup cache
+ m_LookupCache.entry_index = i;
+ m_LookupCache.sample = sample_start;
+
+ return AP4_SUCCESS;
+ }
+
+ // update the upper bound
+ sample_start += entry.m_SampleCount;
+ }
+
+ // sample is greater than the number of samples
+ return AP4_ERROR_OUT_OF_RANGE;
+}
+
+/*----------------------------------------------------------------------
+| AP4_CttsAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_CttsAtom::WriteFields(AP4_ByteStream& stream)
+{
+ AP4_Result result;
+
+ // write the entry count
+ AP4_Cardinal entry_count = m_Entries.ItemCount();
+ result = stream.WriteUI32(entry_count);
+ if (AP4_FAILED(result)) return result;
+
+ // write the entries
+ for (AP4_Ordinal i=0; i<entry_count; i++) {
+ // sample count
+ result = stream.WriteUI32(m_Entries[i].m_SampleCount);
+ if (AP4_FAILED(result)) return result;
+
+ // time offset
+ result = stream.WriteUI32(m_Entries[i].m_SampleOffset);
+ if (AP4_FAILED(result)) return result;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_CttsAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_CttsAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("entry_count", m_Entries.ItemCount());
+
+ if (inspector.GetVerbosity() >= 2) {
+ char header[32];
+ char value[64];
+ for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) {
+ AP4_FormatString(header, sizeof(header), "entry %8d", i);
+ AP4_FormatString(value, sizeof(value), "count=%d, offset=%d",
+ m_Entries[i].m_SampleCount,
+ m_Entries[i].m_SampleOffset);
+ inspector.AddField(header, value);
+ }
+ }
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CttsAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CttsAtom.h new file mode 100644 index 000000000..0f86c8399 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4CttsAtom.h @@ -0,0 +1,96 @@ +/***************************************************************** +| +| AP4 - ctts Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_CTTS_ATOM_H_ +#define _AP4_CTTS_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4Types.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_CttsTableEntry ++---------------------------------------------------------------------*/ +class AP4_CttsTableEntry { + public: + AP4_CttsTableEntry() : + m_SampleCount(0), + m_SampleOffset(0) {} + AP4_CttsTableEntry(AP4_UI32 sample_count, + AP4_UI32 sample_offset) : + m_SampleCount(sample_count), + m_SampleOffset(sample_offset) {} + + AP4_UI32 m_SampleCount; + AP4_UI32 m_SampleOffset; +}; + +/*---------------------------------------------------------------------- +| AP4_CttsAtom ++---------------------------------------------------------------------*/ +class AP4_CttsAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_CttsAtom, AP4_Atom) + + // class methods + static AP4_CttsAtom* Create(AP4_UI32 size, AP4_ByteStream& stream); + + // constructor + AP4_CttsAtom(); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + AP4_Result AddEntry(AP4_UI32 count, AP4_UI32 cts_offset); + AP4_Result GetCtsOffset(AP4_Ordinal sample, AP4_UI32& cts_offset); + +private: + // methods + AP4_CttsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_Array<AP4_CttsTableEntry> m_Entries; + struct { + AP4_Ordinal sample; + AP4_Ordinal entry_index; + } m_LookupCache; +}; + +#endif // _AP4_CTTS_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DataBuffer.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DataBuffer.cpp new file mode 100644 index 000000000..5cd837d3c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DataBuffer.cpp @@ -0,0 +1,207 @@ +/*****************************************************************
+|
+| AP4 - Data Buffer
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4DataBuffer.h"
+#include "Ap4Utils.h"
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::AP4_DataBuffer
++---------------------------------------------------------------------*/
+AP4_DataBuffer::AP4_DataBuffer() :
+ m_BufferIsLocal(true),
+ m_Buffer(NULL),
+ m_BufferSize(0),
+ m_DataSize(0)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::AP4_DataBuffer
++---------------------------------------------------------------------*/
+AP4_DataBuffer::AP4_DataBuffer(AP4_Size buffer_size) :
+ m_BufferIsLocal(true),
+ m_Buffer(NULL),
+ m_BufferSize(buffer_size),
+ m_DataSize(0)
+{
+ m_Buffer = new AP4_Byte[buffer_size];
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::AP4_DataBuffer
++---------------------------------------------------------------------*/
+AP4_DataBuffer::AP4_DataBuffer(const void* data, AP4_Size data_size) :
+ m_BufferIsLocal(true),
+ m_Buffer(NULL),
+ m_BufferSize(data_size),
+ m_DataSize(data_size)
+{
+ if (data && data_size) {
+ m_Buffer = new AP4_Byte[data_size];
+ AP4_CopyMemory(m_Buffer, data, data_size);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::AP4_DataBuffer
++---------------------------------------------------------------------*/
+AP4_DataBuffer::AP4_DataBuffer(const AP4_DataBuffer& other) :
+ m_BufferIsLocal(true),
+ m_Buffer(NULL),
+ m_BufferSize(other.m_DataSize),
+ m_DataSize(other.m_DataSize)
+{
+ m_Buffer = new AP4_Byte[m_BufferSize];
+ AP4_CopyMemory(m_Buffer, other.m_Buffer, m_BufferSize);
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::~AP4_DataBuffer
++---------------------------------------------------------------------*/
+AP4_DataBuffer::~AP4_DataBuffer()
+{
+ if (m_BufferIsLocal) {
+ delete[] m_Buffer;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::Reserve
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataBuffer::Reserve(AP4_Size size)
+{
+ if (size <= m_BufferSize) return AP4_SUCCESS;
+
+ // try doubling the buffer to accomodate for the new size
+ AP4_Size new_size = m_BufferSize*2+1024;
+ if (new_size < size) new_size = size;
+ return SetBufferSize(new_size);
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::SetBuffer
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataBuffer::SetBuffer(AP4_Byte* buffer, AP4_Size buffer_size)
+{
+ if (m_BufferIsLocal) {
+ // destroy the local buffer
+ delete[] m_Buffer;
+ }
+
+ // we're now using an external buffer
+ m_BufferIsLocal = false;
+ m_Buffer = buffer;
+ m_BufferSize = buffer_size;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::SetBufferSize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataBuffer::SetBufferSize(AP4_Size buffer_size)
+{
+ if (m_BufferIsLocal) {
+ return ReallocateBuffer(buffer_size);
+ } else {
+ return AP4_FAILURE; // you cannot change the
+ // buffer management mode
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::SetDataSize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataBuffer::SetDataSize(AP4_Size size)
+{
+ if (size > m_BufferSize) {
+ if (m_BufferIsLocal) {
+ AP4_Result result = ReallocateBuffer(size);
+ if (AP4_FAILED(result)) return result;
+ } else {
+ return AP4_FAILURE;
+ }
+ }
+ m_DataSize = size;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::SetData
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataBuffer::SetData(const AP4_Byte* data, AP4_Size size)
+{
+ if (size > m_BufferSize) {
+ if (m_BufferIsLocal) {
+ AP4_Result result = ReallocateBuffer(size);
+ if (AP4_FAILED(result)) return result;
+ } else {
+ return AP4_FAILURE;
+ }
+ }
+ AP4_CopyMemory(m_Buffer, data, size);
+ m_DataSize = size;
+
+ return AP4_SUCCESS;
+}
+
+
+/*----------------------------------------------------------------------
+| AP4_DataBuffer::ReallocateBuffer
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataBuffer::ReallocateBuffer(AP4_Size size)
+{
+ // check that the existing data fits
+ if (m_DataSize > size) return AP4_FAILURE;
+
+ // allocate a new buffer
+ AP4_Byte* new_buffer = new AP4_Byte[size];
+
+ // copy the contents of the previous buffer ,is any
+ if (m_Buffer && m_DataSize) {
+ AP4_CopyMemory(new_buffer, m_Buffer, m_DataSize);
+ }
+
+ // destroy the previous buffer
+ delete[] m_Buffer;
+
+ // use the new buffer
+ m_Buffer = new_buffer;
+ m_BufferSize = size;
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DataBuffer.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DataBuffer.h new file mode 100644 index 000000000..64e89f981 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DataBuffer.h @@ -0,0 +1,81 @@ +/***************************************************************** +| +| AP4 - Data Buffer Objects +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_DATA_BUFFER_H_ +#define _AP4_DATA_BUFFER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| AP4_DataBuffer ++---------------------------------------------------------------------*/ +class AP4_DataBuffer +{ + public: + // constructors & destructor + AP4_DataBuffer(); + AP4_DataBuffer(AP4_Size size); + AP4_DataBuffer(const void* data, AP4_Size data_size); + AP4_DataBuffer(const AP4_DataBuffer& other); + virtual ~AP4_DataBuffer(); + + // data buffer handling methods + AP4_Result SetBuffer(AP4_Byte* buffer, AP4_Size buffer_size); + AP4_Result SetBufferSize(AP4_Size buffer_size); + AP4_Size GetBufferSize() const { return m_BufferSize; } + + // data handling methods + const AP4_Byte* GetData() const { return m_Buffer; } + AP4_Byte* UseData() { return m_Buffer; }; + AP4_Size GetDataSize() const { return m_DataSize; } + AP4_Result SetDataSize(AP4_Size size); + AP4_Result SetData(const AP4_Byte* data, AP4_Size data_size); + + // memory management + AP4_Result Reserve(AP4_Size size); + + protected: + // members + bool m_BufferIsLocal; + AP4_Byte* m_Buffer; + AP4_Size m_BufferSize; + AP4_Size m_DataSize; + + // methods + AP4_Result ReallocateBuffer(AP4_Size size); + +private: + // forbid this + AP4_DataBuffer& operator=(const AP4_DataBuffer& other); +}; + +#endif // _AP4_DATA_BUFFER_H_ + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DcomAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DcomAtom.cpp new file mode 100644 index 000000000..9d0bcb0dc --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DcomAtom.cpp @@ -0,0 +1,53 @@ +/*****************************************************************
+|
+| AP4 - dcom Atom
+|
+| Copyright 2002 Gilles Boccon-Gibod & Julien Boeuf
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+
+#include "Ap4DcomAtom.h"
+
+/*----------------------------------------------------------------------
+| AP4_DcomAtom::AP4_DcomAtom
++---------------------------------------------------------------------*/
+
+AP4_DcomAtom* +AP4_DcomAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + return new AP4_DcomAtom(size, stream); +} +
+
+AP4_DcomAtom::AP4_DcomAtom(AP4_Size size,
+ AP4_ByteStream& stream)
+ : AP4_Atom(AP4_ATOM_TYPE_DCOM)
+{
+ size -= AP4_ATOM_HEADER_SIZE;
+
+ stream.ReadUI32(m_CompressorSubType);
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DcomAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DcomAtom.h new file mode 100644 index 000000000..4f0e1e8a8 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DcomAtom.h @@ -0,0 +1,58 @@ +/*****************************************************************
+|
+| AP4 - dcom Atom
+|
+| Copyright 2002 Gilles Boccon-Gibod & Julien Boeuf
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_DCOM_ATOM_H_
+#define _AP4_DCOM_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+
+/*----------------------------------------------------------------------
+| AP4_DcomAtom
++---------------------------------------------------------------------*/
+class AP4_DcomAtom : public AP4_Atom
+{
+public:
+ // class methods + static AP4_DcomAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_DcomAtom(AP4_Size size,
+ AP4_ByteStream& stream);
+
+ AP4_Result WriteFields(AP4_ByteStream& stream) { return AP4_FAILURE; }
+
+ AP4_Atom::Type GetCompressorSubType() const { return m_CompressorSubType; }
+
+private:
+ AP4_Atom::Type m_CompressorSubType;
+};
+
+#endif // _AP4_DCOM_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Debug.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Debug.cpp new file mode 100644 index 000000000..ee09ae84d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Debug.cpp @@ -0,0 +1,69 @@ +/***************************************************************** +| +| AP4 - Debug Support +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include <stdarg.h> +#include <stdio.h> + +#include "Ap4Config.h" +#include "Ap4Types.h" +#include "Ap4Utils.h" +#include "Ap4Debug.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int AP4_DEBUG_MAX_BUFFER = 1024; + +/*---------------------------------------------------------------------- +| AP4_Print ++---------------------------------------------------------------------*/ +static void +AP4_Print(const char* message) +{ + printf("%s", message); +} + +/*---------------------------------------------------------------------- +| AP4_Debug ++---------------------------------------------------------------------*/ +void +AP4_Debug(const char* format, ...) +{ + va_list args; + + va_start(args, format); + + char buffer[AP4_DEBUG_MAX_BUFFER]; + AP4_FormatStringVN(buffer, sizeof(buffer), format, args); + AP4_Print(buffer); + + va_end(args); +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Debug.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Debug.h new file mode 100644 index 000000000..cf8613725 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Debug.h @@ -0,0 +1,51 @@ +/***************************************************************** +| +| AP4 - Debug Support +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_DEBUG_H_ +#define _AP4_DEBUG_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Config.h" + +/*---------------------------------------------------------------------- +| AP4_Debug ++---------------------------------------------------------------------*/ +extern void AP4_Debug(const char* format, ...); + +/*---------------------------------------------------------------------- +| AP4_ASSERT ++---------------------------------------------------------------------*/ +#if defined (AP4_CONFIG_HAVE_ASSERT_H) +#include <assert.h> +#define AP4_ASSERT assert +#endif + + +#endif // _AP4_DEBUG_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderConfigDescriptor.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderConfigDescriptor.cpp new file mode 100644 index 000000000..45b348f2d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderConfigDescriptor.cpp @@ -0,0 +1,172 @@ +/***************************************************************** +| +| AP4 - DecoderConfig Descriptors +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4DecoderConfigDescriptor.h" +#include "Ap4DescriptorFactory.h" +#include "Ap4Utils.h" +#include "Ap4ByteStream.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DecoderConfigDescriptor) + +/*---------------------------------------------------------------------- +| AP4_DecoderConfigDescriptor::AP4_DecoderConfigDescriptor ++---------------------------------------------------------------------*/ +AP4_DecoderConfigDescriptor::AP4_DecoderConfigDescriptor( + AP4_UI08 stream_type, + AP4_UI08 oti, + AP4_UI32 buffer_size, + AP4_UI32 max_bitrate, + AP4_UI32 avg_bitrate, + AP4_DecoderSpecificInfoDescriptor* dsi) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_DECODER_CONFIG, 2, 13), + m_StreamType(stream_type), + m_ObjectTypeIndication(oti), + m_UpStream(false), + m_BufferSize(buffer_size), + m_MaxBitrate(max_bitrate), + m_AverageBitrate(avg_bitrate) +{ + if (dsi) { + m_SubDescriptors.Add(dsi); + m_PayloadSize += dsi->GetSize(); + m_HeaderSize = MinHeaderSize(m_PayloadSize); + } +} + +/*---------------------------------------------------------------------- +| AP4_DecoderConfigDescriptor::AP4_DecoderConfigDescriptor ++---------------------------------------------------------------------*/ +AP4_DecoderConfigDescriptor::AP4_DecoderConfigDescriptor( + AP4_ByteStream& stream, AP4_Size header_size, AP4_Size payload_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_DECODER_CONFIG, + header_size, + payload_size) +{ + // record the start position + AP4_Position start; + stream.Tell(start); + + // read descriptor fields + stream.ReadUI08(m_ObjectTypeIndication); + unsigned char bits; + stream.ReadUI08(bits); + m_StreamType = (bits>>2)&0x3F; + m_UpStream = bits&2 ? true:false; + stream.ReadUI24(m_BufferSize); + stream.ReadUI32(m_MaxBitrate); + stream.ReadUI32(m_AverageBitrate); + + // read other descriptors + AP4_SubStream* substream = new AP4_SubStream(stream, start+13, payload_size-13); + AP4_Descriptor* descriptor = NULL; + while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, + descriptor) + == AP4_SUCCESS) { + m_SubDescriptors.Add(descriptor); + } + substream->Release(); +} + +/*---------------------------------------------------------------------- +| AP4_DecoderConfigDescriptor::~AP4_DecoderConfigDescriptor ++---------------------------------------------------------------------*/ +AP4_DecoderConfigDescriptor::~AP4_DecoderConfigDescriptor() +{ + m_SubDescriptors.DeleteReferences(); +} + +/*---------------------------------------------------------------------- +| AP4_DecoderConfigDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DecoderConfigDescriptor::WriteFields(AP4_ByteStream& stream) +{ + stream.WriteUI08(m_ObjectTypeIndication); + AP4_UI08 bits = (m_StreamType<<2) | (m_UpStream? 2 : 0) | 1; + stream.WriteUI08(bits); + stream.WriteUI24(m_BufferSize); + stream.WriteUI32(m_MaxBitrate); + stream.WriteUI32(m_AverageBitrate); + + m_SubDescriptors.Apply(AP4_DescriptorListWriter(stream)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_DecoderConfigDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DecoderConfigDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(), + m_PayloadSize); + inspector.StartElement("[DecoderConfig]", info); + inspector.AddField("stream_type", m_StreamType); + inspector.AddField("object_type", m_ObjectTypeIndication); + inspector.AddField("up_stream", m_UpStream); + inspector.AddField("buffer_size", m_BufferSize); + inspector.AddField("max_bitrate", m_MaxBitrate); + inspector.AddField("avg_bitrate", m_AverageBitrate); + + // inspect children + m_SubDescriptors.Apply(AP4_DescriptorListInspector(inspector)); + + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_DecoderConfigDescriptor::GetDecoderSpecificInfoDescriptor ++---------------------------------------------------------------------*/ +const AP4_DecoderSpecificInfoDescriptor* +AP4_DecoderConfigDescriptor::GetDecoderSpecificInfoDescriptor() const +{ + // find the decoder specific info + AP4_Descriptor* descriptor = NULL; + AP4_Result result = + m_SubDescriptors.Find(AP4_DescriptorFinder(AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO), + descriptor); + + // return it + if (AP4_SUCCEEDED(result)) { + return AP4_DYNAMIC_CAST(AP4_DecoderSpecificInfoDescriptor, descriptor); + } else { + return NULL; + } +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderConfigDescriptor.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderConfigDescriptor.h new file mode 100644 index 000000000..831bbf9e5 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderConfigDescriptor.h @@ -0,0 +1,94 @@ +/***************************************************************** +| +| AP4 - DecoderConfig Descriptor +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_DECODER_CONFIG_DESCRIPTOR_H_ +#define _AP4_DECODER_CONFIG_DESCRIPTOR_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4Descriptor.h" +#include "Ap4DecoderSpecificInfoDescriptor.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_DESCRIPTOR_TAG_DECODER_CONFIG = 0x04; + +/*---------------------------------------------------------------------- +| AP4_DecoderConfigDescriptor ++---------------------------------------------------------------------*/ +class AP4_DecoderConfigDescriptor : public AP4_Descriptor +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DecoderConfigDescriptor, AP4_Descriptor) + + // methods + AP4_DecoderConfigDescriptor(AP4_UI08 stream_type, + AP4_UI08 oti, + AP4_UI32 buffer_size, + AP4_UI32 max_bitrate, + AP4_UI32 avg_bitrate, + AP4_DecoderSpecificInfoDescriptor* dsi); + AP4_DecoderConfigDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size); + virtual ~AP4_DecoderConfigDescriptor(); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + virtual const AP4_DecoderSpecificInfoDescriptor* + GetDecoderSpecificInfoDescriptor() const; + virtual AP4_UI08 GetObjectTypeIndication() const { + return m_ObjectTypeIndication; + } + virtual AP4_UI08 GetStreamType() const { return m_StreamType; } + virtual AP4_UI32 GetBufferSize() const { return m_BufferSize; } + virtual AP4_UI32 GetMaxBitrate() const { return m_MaxBitrate; } + virtual AP4_UI32 GetAvgBitrate() const { return m_AverageBitrate; } + + private: + // members + AP4_UI08 m_StreamType; + AP4_UI08 m_ObjectTypeIndication; + bool m_UpStream; + AP4_UI32 m_BufferSize; + AP4_UI32 m_MaxBitrate; + AP4_UI32 m_AverageBitrate; + mutable AP4_List<AP4_Descriptor> m_SubDescriptors; +}; + +#endif // _AP4_DECODER_CONFIG_DESCRIPTOR_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderSpecificInfoDescriptor.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderSpecificInfoDescriptor.cpp new file mode 100644 index 000000000..8c755964f --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderSpecificInfoDescriptor.cpp @@ -0,0 +1,104 @@ +/***************************************************************** +| +| AP4 - DecoderSpecificInfo Descriptors +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4DecoderSpecificInfoDescriptor.h" +#include "Ap4DescriptorFactory.h" +#include "Ap4Utils.h" +#include "Ap4ByteStream.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DecoderSpecificInfoDescriptor) + +/*---------------------------------------------------------------------- +| AP4_DecoderSpecificInfoDescriptor::AP4_DecoderSpecificInfoDescriptor ++---------------------------------------------------------------------*/ +AP4_DecoderSpecificInfoDescriptor::AP4_DecoderSpecificInfoDescriptor( + const AP4_DataBuffer& data) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO, + MinHeaderSize(data.GetDataSize()), + data.GetDataSize()), + m_Info(data) +{ +} + +/*---------------------------------------------------------------------- +| AP4_DecoderSpecificInfoDescriptor::AP4_DecoderSpecificInfoDescriptor ++---------------------------------------------------------------------*/ +AP4_DecoderSpecificInfoDescriptor::AP4_DecoderSpecificInfoDescriptor( + AP4_ByteStream& stream, AP4_Size header_size, AP4_Size payload_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO, + header_size, payload_size) +{ + m_Info.SetDataSize(payload_size); + stream.Read(m_Info.UseData(), payload_size); +} + +/*---------------------------------------------------------------------- +| AP4_DecoderSpecificInfoDescriptor::~AP4_DecoderSpecificInfoDescriptor ++---------------------------------------------------------------------*/ +AP4_DecoderSpecificInfoDescriptor::~AP4_DecoderSpecificInfoDescriptor() +{ +} + +/*---------------------------------------------------------------------- +| AP4_DecoderSpecificInfoDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DecoderSpecificInfoDescriptor::WriteFields(AP4_ByteStream& stream) +{ + // write the info buffer + if (m_PayloadSize && m_Info.GetDataSize()) { + stream.Write(m_Info.GetData(), m_Info.GetDataSize()); + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_DecoderSpecificInfoDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DecoderSpecificInfoDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char* info = new char[m_Info.GetDataSize()*3+1]; + for (unsigned int i=0; i<m_Info.GetDataSize(); i++) { + AP4_FormatString(&info[i*3], 4, "%02x ", m_Info.UseData()[i]); + } + info[m_Info.GetDataSize()*3] = '\0'; + inspector.AddField("[DecoderSpecificInfo]", info); + delete[] info; + + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderSpecificInfoDescriptor.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderSpecificInfoDescriptor.h new file mode 100644 index 000000000..8f0611c12 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DecoderSpecificInfoDescriptor.h @@ -0,0 +1,73 @@ +/***************************************************************** +| +| AP4 - DecoderSpecificInfo Descriptor +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_DECODER_SPECIFIC_INFO_DESCRIPTOR_H_ +#define _AP4_DECODER_SPECIFIC_INFO_DESCRIPTOR_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4Descriptor.h" +#include "Ap4DataBuffer.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO = 0x05; + +/*---------------------------------------------------------------------- +| AP4_DecoderSpecificInfoDescriptor ++---------------------------------------------------------------------*/ +class AP4_DecoderSpecificInfoDescriptor : public AP4_Descriptor +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DecoderSpecificInfoDescriptor, AP4_Descriptor) + + // methods + AP4_DecoderSpecificInfoDescriptor(const AP4_DataBuffer& data); + AP4_DecoderSpecificInfoDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size); + virtual ~AP4_DecoderSpecificInfoDescriptor(); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + virtual const AP4_DataBuffer& GetDecoderSpecificInfo() const { return m_Info; } + +private: + // members + AP4_DataBuffer m_Info; +}; + +#endif // _AP4_DECODER_SPECIFIC_INFO_DESCRIPTOR_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Descriptor.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Descriptor.cpp new file mode 100644 index 000000000..38fb28988 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Descriptor.cpp @@ -0,0 +1,83 @@ +/***************************************************************** +| +| AP4 - Descriptors +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Descriptor.h" +#include "Ap4Utils.h" +#include "Ap4ByteStream.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_Descriptor) + +/*---------------------------------------------------------------------- +| AP4_Descriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Descriptor::Inspect(AP4_AtomInspector& inspector) +{ + char name[20]; + AP4_FormatString(name, sizeof(name), "[Descriptor:%02x]", m_ClassId); + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(), + m_PayloadSize); + inspector.StartElement(name, info); + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_UnknownDescriptor::AP4_UnknownDescriptor ++---------------------------------------------------------------------*/ +AP4_UnknownDescriptor::AP4_UnknownDescriptor(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(tag, header_size, payload_size) +{ + m_Data.SetDataSize(payload_size); + stream.Read(m_Data.UseData(), payload_size); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_UnknownDescriptor::WriteFields(AP4_ByteStream& stream) +{ + // write the payload + stream.Write(m_Data.GetData(), m_Data.GetDataSize()); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Descriptor.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Descriptor.h new file mode 100644 index 000000000..7fe0717a1 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Descriptor.h @@ -0,0 +1,132 @@ +/***************************************************************** +| +| AP4 - Descriptors +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_DESCRIPTOR_H_ +#define _AP4_DESCRIPTOR_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Expandable.h" +#include "Ap4List.h" +#include "Ap4DynamicCast.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_AtomInspector; + +/*---------------------------------------------------------------------- +| AP4_Descriptor ++---------------------------------------------------------------------*/ +class AP4_Descriptor : public AP4_Expandable +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST(AP4_Descriptor) + + // constructor + AP4_Descriptor(AP4_UI08 tag, AP4_Size header_size, AP4_Size payload_size) : + AP4_Expandable(tag, CLASS_ID_SIZE_08, header_size, payload_size) {} + + // AP4_Exandable methods + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // methods + AP4_UI08 GetTag() { return (AP4_UI08)m_ClassId; } +}; + +/*---------------------------------------------------------------------- +| AP4_UnknownDescriptor ++---------------------------------------------------------------------*/ +class AP4_UnknownDescriptor : public AP4_Descriptor +{ +public: + // contrusctor + AP4_UnknownDescriptor(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size); + + // AP4_Expandable methods + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // members + AP4_DataBuffer m_Data; +}; + +/*---------------------------------------------------------------------- +| AP4_DescriptorFinder ++---------------------------------------------------------------------*/ +class AP4_DescriptorFinder : public AP4_List<AP4_Descriptor>::Item::Finder +{ + public: + AP4_DescriptorFinder(AP4_UI08 tag) : m_Tag(tag) {} + AP4_Result Test(AP4_Descriptor* descriptor) const { + return descriptor->GetTag() == m_Tag ? AP4_SUCCESS : AP4_FAILURE; + } + + private: + AP4_UI08 m_Tag; +}; + +/*---------------------------------------------------------------------- +| AP4_DescriptorListWriter ++---------------------------------------------------------------------*/ +class AP4_DescriptorListWriter : public AP4_List<AP4_Descriptor>::Item::Operator +{ +public: + AP4_DescriptorListWriter(AP4_ByteStream& stream) : + m_Stream(stream) {} + AP4_Result Action(AP4_Descriptor* descriptor) const { + return descriptor->Write(m_Stream); + } + +private: + AP4_ByteStream& m_Stream; +}; + +/*---------------------------------------------------------------------- +| AP4_DescriptorListInspector ++---------------------------------------------------------------------*/ +class AP4_DescriptorListInspector : public AP4_List<AP4_Descriptor>::Item::Operator +{ + public: + AP4_DescriptorListInspector(AP4_AtomInspector& inspector) : + m_Inspector(inspector) {} + AP4_Result Action(AP4_Descriptor* descriptor) const { + descriptor->Inspect(m_Inspector); + return AP4_SUCCESS; + } + + private: + AP4_AtomInspector& m_Inspector; +}; + +#endif // _AP4_DESCRIPTOR_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DescriptorFactory.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DescriptorFactory.cpp new file mode 100644 index 000000000..331a2bc23 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DescriptorFactory.cpp @@ -0,0 +1,135 @@ +/***************************************************************** +| +| AP4 - Descriptor Factory +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4DescriptorFactory.h" +#include "Ap4EsDescriptor.h" +#include "Ap4ObjectDescriptor.h" +#include "Ap4DecoderConfigDescriptor.h" +#include "Ap4DecoderSpecificInfoDescriptor.h" +#include "Ap4SLConfigDescriptor.h" +#include "Ap4Ipmp.h" +#include "Ap4ByteStream.h" + +/*---------------------------------------------------------------------- +| AP4_DescriptorFactory::CreateDescriptorFromStream ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DescriptorFactory::CreateDescriptorFromStream(AP4_ByteStream& stream, + AP4_Descriptor*& descriptor) +{ + AP4_Result result; + + // NULL by default + descriptor = NULL; + + // remember current stream offset + AP4_Position offset; + stream.Tell(offset); + + // read descriptor tag + unsigned char tag; + result = stream.ReadUI08(tag); + if (AP4_FAILED(result)) { + stream.Seek(offset); + return result; + } + + // read descriptor size + unsigned long payload_size = 0; + unsigned int header_size = 1; + unsigned int max = 4; + unsigned char ext = 0; + do { + header_size++; + result = stream.ReadUI08(ext); + if (AP4_FAILED(result)) { + stream.Seek(offset); + return result; + } + payload_size = (payload_size<<7) + (ext&0x7F); + } while (--max && (ext&0x80)); + + // create the descriptor + switch (tag) { + case AP4_DESCRIPTOR_TAG_OD: + case AP4_DESCRIPTOR_TAG_MP4_OD: + descriptor = new AP4_ObjectDescriptor(stream, tag, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_IOD: + case AP4_DESCRIPTOR_TAG_MP4_IOD: + descriptor = new AP4_InitialObjectDescriptor(stream, tag, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_ES_ID_INC: + descriptor = new AP4_EsIdIncDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_ES_ID_REF: + descriptor = new AP4_EsIdRefDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_ES: + descriptor = new AP4_EsDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_DECODER_CONFIG: + descriptor = new AP4_DecoderConfigDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_DECODER_SPECIFIC_INFO: + descriptor = new AP4_DecoderSpecificInfoDescriptor(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_SL_CONFIG: + if (payload_size != 1) return AP4_ERROR_INVALID_FORMAT; + descriptor = new AP4_SLConfigDescriptor(header_size); + break; + + case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER: + descriptor = new AP4_IpmpDescriptorPointer(stream, header_size, payload_size); + break; + + case AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR: + descriptor = new AP4_IpmpDescriptor(stream, header_size, payload_size); + break; + + default: + descriptor = new AP4_UnknownDescriptor(stream, tag, header_size, payload_size); + break; + } + + // skip to the end of the descriptor + stream.Seek(offset+header_size+payload_size); + + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DescriptorFactory.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DescriptorFactory.h new file mode 100644 index 000000000..9fe8bd0c8 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DescriptorFactory.h @@ -0,0 +1,54 @@ +/***************************************************************** +| +| AP4 - Descriptor Factory +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_DESCRIPTOR_FACTORY_H_ +#define _AP4_DESCRIPTOR_FACTORY_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_Descriptor; + +/*---------------------------------------------------------------------- +| AP4_DescriptorFactory ++---------------------------------------------------------------------*/ +class AP4_DescriptorFactory +{ + public: + // class methods + static AP4_Result CreateDescriptorFromStream(AP4_ByteStream& stream, + AP4_Descriptor*& descriptor); +}; + +#endif // _AP4_DESCRIPTOR_FACTORY_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DrefAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DrefAtom.cpp new file mode 100644 index 000000000..df83ecc1e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DrefAtom.cpp @@ -0,0 +1,105 @@ +/***************************************************************** +| +| AP4 - dref Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4DrefAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" +#include "Ap4ContainerAtom.h" + +/*---------------------------------------------------------------------- +| AP4_DrefAtom::Create ++---------------------------------------------------------------------*/ +AP4_DrefAtom* +AP4_DrefAtom::Create(AP4_UI32 size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_DrefAtom(size, version, flags, stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_DrefAtom::AP4_DrefAtom ++---------------------------------------------------------------------*/ +AP4_DrefAtom::AP4_DrefAtom(AP4_Atom** refs, AP4_Cardinal refs_count) : + AP4_ContainerAtom(AP4_ATOM_TYPE_DREF, (AP4_UI32)0, (AP4_UI32)0) +{ + m_Size32 += 4; + for (unsigned i=0; i<refs_count; i++) { + m_Children.Add(refs[i]); + m_Size32 += (AP4_UI32)refs[i]->GetSize(); + } +} + +/*---------------------------------------------------------------------- +| AP4_DrefAtom::AP4_DrefAtom ++---------------------------------------------------------------------*/ +AP4_DrefAtom::AP4_DrefAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_ContainerAtom(AP4_ATOM_TYPE_DREF, size, false, version, flags) +{ + // read the number of entries + AP4_UI32 entry_count; + stream.ReadUI32(entry_count); + + // read children + AP4_LargeSize bytes_available = size-AP4_FULL_ATOM_HEADER_SIZE-4; + while (entry_count--) { + AP4_Atom* atom; + while (AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(stream, + bytes_available, + atom))) { + m_Children.Add(atom); + } + } +} + +/*---------------------------------------------------------------------- +| AP4_DrefAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DrefAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the number of entries + result = stream.WriteUI32(m_Children.ItemCount()); + if (AP4_FAILED(result)) return result; + + // write the children + return m_Children.Apply(AP4_AtomListWriter(stream)); +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DrefAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DrefAtom.h new file mode 100644 index 000000000..092e959db --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DrefAtom.h @@ -0,0 +1,68 @@ +/***************************************************************** +| +| AP4 - dref Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_DREF_ATOM_H_ +#define _AP4_DREF_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4ContainerAtom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_AtomFactory; + +/*---------------------------------------------------------------------- +| AP4_DrefAtom ++---------------------------------------------------------------------*/ +class AP4_DrefAtom : public AP4_ContainerAtom +{ +public: + // class methods + static AP4_DrefAtom* Create(AP4_UI32 size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + AP4_DrefAtom(AP4_Atom** refs, AP4_Cardinal refs_count); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_DrefAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); +}; + +#endif // _AP4_DREF_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DynamicCast.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DynamicCast.h new file mode 100644 index 000000000..2bc75d441 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4DynamicCast.h @@ -0,0 +1,86 @@ +/***************************************************************** +| +| AP4 - Target Platform and Compiler Configuration +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ +/** + * @file + * @brief Dynamic Cast Support + */ +#ifndef _AP4_DYNAMIC_CAST_H_ +#define _AP4_DYNAMIC_CAST_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Config.h" + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#if defined(AP4_CONFIG_NO_RTTI) +#define AP4_DYNAMIC_CAST(_class,_object) \ +( ((_object)==0) ? 0 : reinterpret_cast<_class*>((_object)->DynamicCast(&_class::_class_##_class)) ) +#define AP4_IMPLEMENT_DYNAMIC_CAST(_class) \ +static int _class_##_class; \ +virtual void* DynamicCast(const void* class_anchor) { \ + if (class_anchor == &_class::_class_##_class) { \ + return static_cast<_class*>(this); \ + } \ + return NULL; \ +} +#define AP4_IMPLEMENT_DYNAMIC_CAST_D(_class,_superclass)\ +static int _class_##_class; \ +virtual void* DynamicCast(const void* class_anchor) { \ + if (class_anchor == &_class::_class_##_class) { \ + return static_cast<_class*>(this); \ + } else { \ + return _superclass::DynamicCast(class_anchor); \ + } \ +} +#define AP4_IMPLEMENT_DYNAMIC_CAST_D2(_class,_superclass,_mixin)\ +static int _class_##_class; \ +virtual void* DynamicCast(const void* class_anchor) { \ + if (class_anchor == &_class::_class_##_class) { \ + return static_cast<_class*>(this); \ + } else { \ + void* sup = _superclass::DynamicCast(class_anchor); \ + if (sup) return sup; \ + return _mixin::DynamicCast(class_anchor); \ + } \ +} +#define AP4_DEFINE_DYNAMIC_CAST_ANCHOR(_class) int _class::_class_##_class = 0; + +#else + +#define AP4_DYNAMIC_CAST(_class,_object) dynamic_cast<_class*>(_object) +#define AP4_IMPLEMENT_DYNAMIC_CAST(_class) +#define AP4_IMPLEMENT_DYNAMIC_CAST_D(_class,_superclass) +#define AP4_IMPLEMENT_DYNAMIC_CAST_D2(_class,_superclass,_mixin) +#define AP4_DEFINE_DYNAMIC_CAST_ANCHOR(_class) + +#endif + +#endif // _AP4_DYNAMIC_CAST_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ElstAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ElstAtom.cpp new file mode 100644 index 000000000..73a2c0920 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ElstAtom.cpp @@ -0,0 +1,128 @@ +/***************************************************************** +| +| AP4 - elst Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4ElstAtom.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_ElstAtom::Create ++---------------------------------------------------------------------*/ +AP4_ElstAtom* +AP4_ElstAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version > 1) return NULL; + return new AP4_ElstAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_ElstAtom::AP4_ElstAtom ++---------------------------------------------------------------------*/ +AP4_ElstAtom::AP4_ElstAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_ELST, size, version, flags) +{ + AP4_UI32 entry_count; + stream.ReadUI32(entry_count); + m_Entries.EnsureCapacity(entry_count); + for (AP4_UI32 i=0; i<entry_count; i++) { + AP4_UI16 media_rate; + AP4_UI16 zero; + if (version == 0) { + AP4_UI32 segment_duration; + AP4_UI32 media_time; + stream.ReadUI32(segment_duration); + stream.ReadUI32(media_time); + stream.ReadUI16(media_rate); + stream.ReadUI16(zero); + m_Entries.Append(AP4_ElstEntry(segment_duration, media_time, media_rate)); + } else { + AP4_UI64 segment_duration; + AP4_UI64 media_time; + stream.ReadUI64(segment_duration); + stream.ReadUI64(media_time); + stream.ReadUI16(media_rate); + stream.ReadUI16(zero); + m_Entries.Append(AP4_ElstEntry(segment_duration, media_time, media_rate)); + } + } +} + +/*---------------------------------------------------------------------- +| AP4_ElstAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ElstAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + result = stream.WriteUI32(m_Entries.ItemCount()); + if (AP4_FAILED(result)) return result; + for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) { + if (m_Version == 0) { + result = stream.WriteUI32((AP4_UI32)m_Entries[i].m_SegmentDuration); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_Entries[i].m_MediaTime); + if (AP4_FAILED(result)) return result; + } else { + result = stream.WriteUI64(m_Entries[i].m_SegmentDuration); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_Entries[i].m_MediaTime); + if (AP4_FAILED(result)) return result; + } + result = stream.WriteUI16(m_Entries[i].m_MediaRate); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI16(0); + if (AP4_FAILED(result)) return result; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_ElstAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ElstAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("entry count", m_Entries.ItemCount()); + for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) { + inspector.AddField("entry/segment duration", (AP4_UI32)m_Entries[i].m_SegmentDuration); + inspector.AddField("entry/media time", (AP4_SI32)m_Entries[i].m_MediaTime); + inspector.AddField("entry/media rate", (AP4_UI16)m_Entries[i].m_MediaRate); + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ElstAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ElstAtom.h new file mode 100644 index 000000000..d613bf6bd --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ElstAtom.h @@ -0,0 +1,80 @@ +/***************************************************************** +| +| AP4 - elst Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_ELST_ATOM_H_ +#define _AP4_ELST_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_ElstAtom ++---------------------------------------------------------------------*/ +class AP4_ElstEntry { +public: + AP4_ElstEntry(AP4_UI64 segment_duration = 0, AP4_SI64 media_time = 0, AP4_UI16 media_rate = 1) : + m_SegmentDuration(segment_duration), + m_MediaTime(media_time), + m_MediaRate(media_rate) {} + + AP4_UI64 m_SegmentDuration; + AP4_SI64 m_MediaTime; + AP4_UI16 m_MediaRate; +}; + +class AP4_ElstAtom : public AP4_Atom +{ +public: + // class methods + static AP4_ElstAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_ElstAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_Array<AP4_ElstEntry> m_Entries; +}; + +#endif // _AP4_ELST_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsDescriptor.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsDescriptor.cpp new file mode 100644 index 000000000..065d6f513 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsDescriptor.cpp @@ -0,0 +1,307 @@ +/***************************************************************** +| +| AP4 - ES Descriptors +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4EsDescriptor.h" +#include "Ap4DescriptorFactory.h" +#include "Ap4Utils.h" +#include "Ap4ByteStream.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_EsDescriptor) +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_EsIdIncDescriptor) +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_EsIdRefDescriptor) + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor::AP4_EsDescriptor ++---------------------------------------------------------------------*/ +AP4_EsDescriptor::AP4_EsDescriptor(AP4_UI16 es_id) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES, 2, 2+1), + m_EsId(es_id), + m_OcrEsId(0), + m_Flags(0), + m_StreamPriority(0), + m_DependsOn(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor::AP4_EsDescriptor ++---------------------------------------------------------------------*/ +AP4_EsDescriptor::AP4_EsDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES, header_size, payload_size) +{ + AP4_Position start; + stream.Tell(start); + + // read descriptor fields + stream.ReadUI16(m_EsId); + unsigned char bits; + stream.ReadUI08(bits); + m_Flags = (bits>>5)&7; + m_StreamPriority = bits&0x1F; + if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_STREAM_DEPENDENCY) { + stream.ReadUI16(m_DependsOn); + } else { + m_DependsOn = 0; + } + if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) { + unsigned char url_length; + stream.ReadUI08(url_length); + if (url_length) { + char* url = new char[url_length+1]; + if (url) { + stream.Read(url, url_length); + url[url_length] = '\0'; + m_Url = url; + delete[] url; + } + } + } + if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) { + stream.ReadUI16(m_OcrEsId); + } else { + m_OcrEsId = 0; + } + + // read other descriptors + AP4_Position offset; + stream.Tell(offset); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, + payload_size-AP4_Size(offset-start)); + AP4_Descriptor* descriptor = NULL; + while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, + descriptor) + == AP4_SUCCESS) { + m_SubDescriptors.Add(descriptor); + } + substream->Release(); +} + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor::~AP4_EsDescriptor ++---------------------------------------------------------------------*/ +AP4_EsDescriptor::~AP4_EsDescriptor() +{ + m_SubDescriptors.DeleteReferences(); +} + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsDescriptor::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // es id + result = stream.WriteUI16(m_EsId); + if (AP4_FAILED(result)) return result; + + // flags and other bits + AP4_UI08 bits = m_StreamPriority | (AP4_UI08)(m_Flags<<5); + result = stream.WriteUI08(bits); + if (AP4_FAILED(result)) return result; + + // optional fields + if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_STREAM_DEPENDENCY) { + result = stream.WriteUI16(m_DependsOn); + if (AP4_FAILED(result)) return result; + } + if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_URL) { + result = stream.WriteUI08((AP4_UI08)m_Url.GetLength()); + if (AP4_FAILED(result)) return result; + result = stream.WriteString(m_Url.GetChars()); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI08(0); + if (AP4_FAILED(result)) return result; + } + if (m_Flags & AP4_ES_DESCRIPTOR_FLAG_OCR_STREAM) { + result = stream.WriteUI16(m_OcrEsId); + if (AP4_FAILED(result)) return result; + } + + // write the sub descriptors + m_SubDescriptors.Apply(AP4_DescriptorListWriter(stream)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + inspector.StartElement("[ESDescriptor]", info); + inspector.AddField("es_id", m_EsId); + inspector.AddField("stream_priority", m_StreamPriority); + + // inspect children + m_SubDescriptors.Apply(AP4_DescriptorListInspector(inspector)); + + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor::AddSubDescriptor ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsDescriptor::AddSubDescriptor(AP4_Descriptor* descriptor) +{ + m_SubDescriptors.Add(descriptor); + m_PayloadSize += descriptor->GetSize(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor::GetDecoderConfigDescriptor ++---------------------------------------------------------------------*/ +const AP4_DecoderConfigDescriptor* +AP4_EsDescriptor::GetDecoderConfigDescriptor() const +{ + // find the decoder config descriptor + AP4_Descriptor* descriptor = NULL; + AP4_Result result = + m_SubDescriptors.Find(AP4_DescriptorFinder(AP4_DESCRIPTOR_TAG_DECODER_CONFIG), + descriptor); + + // return it + if (AP4_SUCCEEDED(result)) { + return AP4_DYNAMIC_CAST(AP4_DecoderConfigDescriptor, descriptor); + } else { + return NULL; + } +} + +/*---------------------------------------------------------------------- +| AP4_EsIdIncDescriptor::AP4_EsIdIncDescriptor ++---------------------------------------------------------------------*/ +AP4_EsIdIncDescriptor::AP4_EsIdIncDescriptor(AP4_UI32 track_id) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES_ID_INC, 2, 4), + m_TrackId(track_id) +{ +} + +/*---------------------------------------------------------------------- +| AP4_EsIdIncDescriptor::AP4_EsIdIncDescriptor ++---------------------------------------------------------------------*/ +AP4_EsIdIncDescriptor::AP4_EsIdIncDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES_ID_INC, header_size, payload_size) +{ + // read the track id + stream.ReadUI32(m_TrackId); +} + +/*---------------------------------------------------------------------- +| AP4_EsIdIncescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsIdIncDescriptor::WriteFields(AP4_ByteStream& stream) +{ + // track id + return stream.WriteUI32(m_TrackId); +} + +/*---------------------------------------------------------------------- +| AP4_EsIdIncDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsIdIncDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + inspector.StartElement("[ES_ID_Inc]", info); + inspector.AddField("track_id", m_TrackId); + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_EsIdRefDescriptor::AP4_EsIdRefDescriptor ++---------------------------------------------------------------------*/ +AP4_EsIdRefDescriptor::AP4_EsIdRefDescriptor(AP4_UI16 ref_index) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES_ID_REF, 2, 2), + m_RefIndex(ref_index) +{ +} + +/*---------------------------------------------------------------------- +| AP4_EsIdRefDescriptor::AP4_EsIdRefDescriptor ++---------------------------------------------------------------------*/ +AP4_EsIdRefDescriptor::AP4_EsIdRefDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_ES_ID_REF, header_size, payload_size) +{ + // read the ref index + stream.ReadUI16(m_RefIndex); +} + +/*---------------------------------------------------------------------- +| AP4_EsIdRefDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsIdRefDescriptor::WriteFields(AP4_ByteStream& stream) +{ + // ref index + return stream.WriteUI16(m_RefIndex); +} + +/*---------------------------------------------------------------------- +| AP4_EsIdRefDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsIdRefDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + inspector.StartElement("[ES_ID_Ref]", info); + inspector.AddField("ref_index", m_RefIndex); + inspector.EndElement(); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsDescriptor.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsDescriptor.h new file mode 100644 index 000000000..d971e7e05 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsDescriptor.h @@ -0,0 +1,134 @@ +/***************************************************************** +| +| AP4 - ES Descriptor +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_ES_DESCRIPTOR_H_ +#define _AP4_ES_DESCRIPTOR_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4List.h" +#include "Ap4String.h" +#include "Ap4Descriptor.h" +#include "Ap4DecoderConfigDescriptor.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_DESCRIPTOR_TAG_ES = 0x03; +const AP4_UI08 AP4_DESCRIPTOR_TAG_ES_ID_INC = 0x0E; +const AP4_UI08 AP4_DESCRIPTOR_TAG_ES_ID_REF = 0x0F; + +const int AP4_ES_DESCRIPTOR_FLAG_STREAM_DEPENDENCY = 1; +const int AP4_ES_DESCRIPTOR_FLAG_URL = 2; +const int AP4_ES_DESCRIPTOR_FLAG_OCR_STREAM = 4; + +/*---------------------------------------------------------------------- +| AP4_EsDescriptor ++---------------------------------------------------------------------*/ +class AP4_EsDescriptor : public AP4_Descriptor +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_EsDescriptor, AP4_Descriptor) + + // methods + AP4_EsDescriptor(AP4_UI16 es_id); + AP4_EsDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size); + ~AP4_EsDescriptor(); + virtual AP4_Result AddSubDescriptor(AP4_Descriptor* descriptor); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + virtual const AP4_DecoderConfigDescriptor* GetDecoderConfigDescriptor() const; + + private: + // members + unsigned short m_EsId; + unsigned short m_OcrEsId; + AP4_Flags m_Flags; + unsigned char m_StreamPriority; + unsigned short m_DependsOn; + AP4_String m_Url; + mutable AP4_List<AP4_Descriptor> m_SubDescriptors; +}; + +/*---------------------------------------------------------------------- +| AP4_EsIdIncDescriptor ++---------------------------------------------------------------------*/ +class AP4_EsIdIncDescriptor : public AP4_Descriptor +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_EsIdIncDescriptor, AP4_Descriptor) + + // methods + AP4_EsIdIncDescriptor(AP4_UI32 track_id); + AP4_EsIdIncDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + AP4_UI32 GetTrackId() const { return m_TrackId; } + + private: + // members + AP4_UI32 m_TrackId; +}; + +/*---------------------------------------------------------------------- +| AP4_EsIdRefDescriptor ++---------------------------------------------------------------------*/ +class AP4_EsIdRefDescriptor : public AP4_Descriptor +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_EsIdRefDescriptor, AP4_Descriptor) + + // methods + AP4_EsIdRefDescriptor(AP4_UI16 ref_index); + AP4_EsIdRefDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + AP4_UI16 GetRefIndex() const { return m_RefIndex; } + + private: + // members + AP4_UI16 m_RefIndex; +}; + +#endif // _AP4_ES_DESCRIPTOR_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsdsAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsdsAtom.cpp new file mode 100644 index 000000000..b03e73a91 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsdsAtom.cpp @@ -0,0 +1,115 @@ +/***************************************************************** +| +| AP4 - esds Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4EsdsAtom.h" +#include "Ap4DescriptorFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_EsdsAtom) + +/*---------------------------------------------------------------------- +| AP4_EsdsAtom::Create ++---------------------------------------------------------------------*/ +AP4_EsdsAtom* +AP4_EsdsAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_EsdsAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_EsdsAtom::AP4_EsdsAtom ++---------------------------------------------------------------------*/ +AP4_EsdsAtom::AP4_EsdsAtom(AP4_EsDescriptor* descriptor) : + AP4_Atom(AP4_ATOM_TYPE_ESDS, AP4_FULL_ATOM_HEADER_SIZE, 0, 0), + m_EsDescriptor(descriptor) +{ + if (m_EsDescriptor) m_Size32 += m_EsDescriptor->GetSize(); +} + +/*---------------------------------------------------------------------- +| AP4_EsdsAtom::AP4_EsdsAtom ++---------------------------------------------------------------------*/ +AP4_EsdsAtom::AP4_EsdsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_ESDS, size, version, flags) +{ + // read descriptor + AP4_Descriptor* descriptor = NULL; + if (AP4_DescriptorFactory::CreateDescriptorFromStream(stream, descriptor) + == AP4_SUCCESS) { + m_EsDescriptor = AP4_DYNAMIC_CAST(AP4_EsDescriptor, descriptor); + } else { + m_EsDescriptor = NULL; + } +} + +/*---------------------------------------------------------------------- +| AP4_EsdsAtom::~AP4_EsdsAtom ++---------------------------------------------------------------------*/ +AP4_EsdsAtom::~AP4_EsdsAtom() +{ + delete m_EsDescriptor; +} + +/*---------------------------------------------------------------------- +| AP4_EsdsAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsdsAtom::WriteFields(AP4_ByteStream& stream) +{ + // write the es descriptor + if (m_EsDescriptor) return m_EsDescriptor->Write(stream); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_EsdsAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_EsdsAtom::InspectFields(AP4_AtomInspector& inspector) +{ + // inspect descriptor + if (m_EsDescriptor) { + m_EsDescriptor->Inspect(inspector); + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsdsAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsdsAtom.h new file mode 100644 index 000000000..962f9e2c3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4EsdsAtom.h @@ -0,0 +1,73 @@ +/***************************************************************** +| +| AP4 - esds Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_ESDS_ATOM_H_ +#define _AP4_ESDS_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4EsDescriptor.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_EsdsAtom ++---------------------------------------------------------------------*/ +class AP4_EsdsAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_EsdsAtom, AP4_Atom) + + // class methods + static AP4_EsdsAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_EsdsAtom(AP4_EsDescriptor* descriptor); + ~AP4_EsdsAtom(); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + const AP4_EsDescriptor* GetEsDescriptor() const { return m_EsDescriptor; } + +private: + // methods + AP4_EsdsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_EsDescriptor* m_EsDescriptor; +}; + +#endif // _AP4_ESDS_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Expandable.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Expandable.cpp new file mode 100644 index 000000000..a0fa39601 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Expandable.cpp @@ -0,0 +1,126 @@ +/***************************************************************** +| +| AP4 - Expandable base class +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Debug.h" +#include "Ap4Descriptor.h" +#include "Ap4Utils.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_Expandable::MinHeaderSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_Expandable::MinHeaderSize(AP4_Size payload_size) +{ + // compute how many bytes are needed to encode the payload size + // plus tag + return 2+(payload_size/128); +} + +/*---------------------------------------------------------------------- +| AP4_Expandable::AP4_Expandable ++---------------------------------------------------------------------*/ +AP4_Expandable::AP4_Expandable(AP4_UI32 class_id, + ClassIdSize class_id_size, + AP4_Size header_size, + AP4_Size payload_size) : + m_ClassId(class_id), + m_ClassIdSize(class_id_size), + m_HeaderSize(header_size), + m_PayloadSize(payload_size) +{ + AP4_ASSERT(header_size >= 1+1); + AP4_ASSERT(header_size <= 1+4); +} + +/*---------------------------------------------------------------------- +| AP4_Expandable::Write ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Expandable::Write(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the class id + switch (m_ClassIdSize) { + case CLASS_ID_SIZE_08: + result = stream.WriteUI08((AP4_UI08)m_ClassId); + if (AP4_FAILED(result)) return result; + break; + + default: + return AP4_ERROR_INTERNAL; + } + + // write the size + AP4_ASSERT(m_HeaderSize-1 <= 8); + AP4_ASSERT(m_HeaderSize >= 2); + unsigned int size = m_PayloadSize; + unsigned char bytes[8]; + + // last bytes of the encoded size + bytes[m_HeaderSize-2] = size&0x7F; + + // leading bytes of the encoded size + for (int i=m_HeaderSize-3; i>=0; i--) { + // move to the next 7 bits + size >>= 7; + + // output a byte with a top bit marker + bytes[i] = (size&0x7F) | 0x80; + } + + result = stream.Write(bytes, m_HeaderSize-1); + if (AP4_FAILED(result)) return result; + + // write the fields + WriteFields(stream); + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_Expandable::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Expandable::Inspect(AP4_AtomInspector& inspector) +{ + char name[6]; + AP4_FormatString(name, sizeof(name), "[#:%02x]", m_ClassId); + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(), + m_PayloadSize); + inspector.StartElement(name, info); + inspector.EndElement(); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Expandable.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Expandable.h new file mode 100644 index 000000000..63949eeb5 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Expandable.h @@ -0,0 +1,98 @@ +/***************************************************************** +| +| AP4 - Expandable base class +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_EXPANDABLE_H_ +#define _AP4_EXPANDABLE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4DataBuffer.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_AtomInspector; + +/*---------------------------------------------------------------------- +| AP4_Expandable ++---------------------------------------------------------------------*/ +class AP4_Expandable +{ + public: + // types + enum ClassIdSize { + CLASS_ID_SIZE_08 + }; + + // class methods + static AP4_Size MinHeaderSize(AP4_Size payload_size); + + // methods + AP4_Expandable(AP4_UI32 class_id, + ClassIdSize class_id_size, + AP4_Size header_size, + AP4_Size payload_size); + virtual ~AP4_Expandable() {} + AP4_UI32 GetClassId() { return m_ClassId; } + AP4_Size GetSize() { return m_PayloadSize+m_HeaderSize; } + AP4_Size GetHeaderSize() { return m_HeaderSize; } + virtual AP4_Result Write(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream) = 0; + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + protected: + // members + AP4_UI32 m_ClassId; + ClassIdSize m_ClassIdSize; + AP4_Size m_HeaderSize; + AP4_Size m_PayloadSize; +}; + +/*---------------------------------------------------------------------- +| AP4_UnknownExpandable ++---------------------------------------------------------------------*/ +class AP4_UnknownExpandable : public AP4_Expandable +{ +public: + // methods + AP4_UnknownExpandable(AP4_ByteStream& stream, + AP4_UI32 class_id, + ClassIdSize class_id_size, + AP4_Size header_size, + AP4_Size payload_size); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // members + AP4_DataBuffer m_Data; +}; + +#endif // _AP4_EXPANDABLE_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4File.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4File.cpp new file mode 100644 index 000000000..baedd893a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4File.cpp @@ -0,0 +1,148 @@ +/*****************************************************************
+|
+| AP4 - File
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4File.h"
+#include "Ap4Atom.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4MoovAtom.h"
+#include "Ap4MvhdAtom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4Movie.h"
+#include "Ap4FtypAtom.h"
+#include "Ap4MetaData.h"
+
+/*----------------------------------------------------------------------
+| AP4_File::AP4_File
++---------------------------------------------------------------------*/
+AP4_File::AP4_File(AP4_Movie* movie) :
+ m_Movie(movie),
+ m_FileType(NULL),
+ m_MetaData(NULL),
+ m_MoovIsBeforeMdat(true)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_File::AP4_File
++---------------------------------------------------------------------*/
+AP4_File::AP4_File(AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory,
+ bool moov_only) :
+ m_Movie(NULL),
+ m_FileType(NULL),
+ m_MetaData(NULL),
+ m_MoovIsBeforeMdat(true)
+{
+ // parse top-level atoms
+ AP4_Atom* atom;
+ AP4_Position stream_position;
+ bool keep_parsing = true;
+ while (keep_parsing &&
+ AP4_SUCCEEDED(stream.Tell(stream_position)) &&
+ AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(stream, atom))) {
+ AddChild(atom);
+ switch (atom->GetType()) {
+ case AP4_ATOM_TYPE_MOOV:
+ m_Movie = new AP4_Movie(AP4_DYNAMIC_CAST(AP4_MoovAtom, atom), stream, false);
+ if (moov_only) keep_parsing = false;
+ break;
+
+ case AP4_ATOM_TYPE_FTYP:
+ m_FileType = AP4_DYNAMIC_CAST(AP4_FtypAtom, atom);
+ break;
+
+ case AP4_ATOM_TYPE_MDAT:
+ // see if we are before the moov atom
+ if (m_Movie == NULL) m_MoovIsBeforeMdat = false;
+ break;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_File::~AP4_File
++---------------------------------------------------------------------*/
+AP4_File::~AP4_File()
+{
+ delete m_Movie;
+ delete m_MetaData;
+}
+
+/*----------------------------------------------------------------------
+| AP4_File::Inspect
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_File::Inspect(AP4_AtomInspector& inspector)
+{
+ // dump the moov atom first
+ if (m_Movie) m_Movie->Inspect(inspector);
+
+ // dump the other atoms
+ m_Children.Apply(AP4_AtomListInspector(inspector));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_File::SetFileType
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_File::SetFileType(AP4_UI32 major_brand,
+ AP4_UI32 minor_version,
+ AP4_UI32* compatible_brands,
+ AP4_Cardinal compatible_brand_count)
+{
+ if (m_FileType) {
+ RemoveChild(m_FileType);
+ delete m_FileType;
+ }
+ m_FileType = new AP4_FtypAtom(major_brand,
+ minor_version,
+ compatible_brands,
+ compatible_brand_count);
+ AddChild(m_FileType, 0);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_File::GetMetaData
++---------------------------------------------------------------------*/
+const AP4_MetaData*
+AP4_File::GetMetaData()
+{
+ if (m_MetaData == NULL) {
+ m_MetaData = new AP4_MetaData(this);
+ }
+
+ return m_MetaData;
+}
+
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4File.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4File.h new file mode 100644 index 000000000..180c31819 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4File.h @@ -0,0 +1,148 @@ +/***************************************************************** +| +| AP4 - File +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_FILE_H_ +#define _AP4_FILE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4Atom.h" +#include "Ap4AtomFactory.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_Movie; +class AP4_FtypAtom; +class AP4_MetaData; + +/*---------------------------------------------------------------------- +| file type/brands ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_FILE_BRAND_QT__ = AP4_ATOM_TYPE('q','t',' ',' '); +const AP4_UI32 AP4_FILE_BRAND_ISOM = AP4_ATOM_TYPE('i','s','o','m'); +const AP4_UI32 AP4_FILE_BRAND_MP41 = AP4_ATOM_TYPE('m','p','4','1'); +const AP4_UI32 AP4_FILE_BRAND_MP42 = AP4_ATOM_TYPE('m','p','4','2'); +const AP4_UI32 AP4_FILE_BRAND_3GP1 = AP4_ATOM_TYPE('3','g','p','1'); +const AP4_UI32 AP4_FILE_BRAND_3GP2 = AP4_ATOM_TYPE('3','g','p','2'); +const AP4_UI32 AP4_FILE_BRAND_3GP3 = AP4_ATOM_TYPE('3','g','p','3'); +const AP4_UI32 AP4_FILE_BRAND_3GP4 = AP4_ATOM_TYPE('3','g','p','4'); +const AP4_UI32 AP4_FILE_BRAND_3GP5 = AP4_ATOM_TYPE('3','g','p','5'); +const AP4_UI32 AP4_FILE_BRAND_3G2A = AP4_ATOM_TYPE('3','g','2','a'); +const AP4_UI32 AP4_FILE_BRAND_MMP4 = AP4_ATOM_TYPE('m','m','p','4'); +const AP4_UI32 AP4_FILE_BRAND_M4A_ = AP4_ATOM_TYPE('M','4','A',' '); +const AP4_UI32 AP4_FILE_BRAND_M4P_ = AP4_ATOM_TYPE('M','4','P',' '); +const AP4_UI32 AP4_FILE_BRAND_MJP2 = AP4_ATOM_TYPE('m','j','p','2'); + +/*---------------------------------------------------------------------- +| AP4_File ++---------------------------------------------------------------------*/ + +/** + * The AP4_File object is the top level object for MP4 Files. + */ + +class AP4_File : public AP4_AtomParent { +public: + // constructors and destructor + /** + * Constructs an AP4_File from an AP4_Movie (used for writing) + * @param movie the movie + */ + AP4_File(AP4_Movie* movie = NULL); + + /** + * Constructs an AP4_File from a stream + * @param stream the stream containing the data of the file + * @param factory the atom factory that will be used to parse the stream + * @param moov_only indicates whether parsing of the atoms should stop + * when the moov atom is found or if all atoms should be parsed until the + * end of the file. + */ + AP4_File(AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory = AP4_DefaultAtomFactory::Instance, + bool moov_only = false); + + /** + * Destroys the AP4_File instance + */ + virtual ~AP4_File(); + + /** + * Get the top level atoms of the file + */ + AP4_List<AP4_Atom>& GetTopLevelAtoms() { return m_Children; } + + /** + * Get the AP4_Movie object of this file + */ + AP4_Movie* GetMovie() { return m_Movie; } + + + /** + * Get the file type atom of this file + */ + AP4_FtypAtom* GetFileType() { return m_FileType; } + + /** + * Set the file type. Will internally create an AP4_Ftyp atom + * and attach it to the file + */ + AP4_Result SetFileType(AP4_UI32 major_brand, + AP4_UI32 minor_version, + AP4_UI32* compatible_brands = NULL, + AP4_Cardinal compatible_brand_count = 0); + + /** + * Ask whether the moov atom appears before the first mdat atom + */ + bool IsMoovBeforeMdat() const { return m_MoovIsBeforeMdat; } + + /** + * Get the file's metadata description + */ + const AP4_MetaData* GetMetaData(); + + /** + * Inspect the content of the file with an AP4_AtomInspector + */ + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + +private: + // members + AP4_Movie* m_Movie; + AP4_FtypAtom* m_FileType; + AP4_MetaData* m_MetaData; + bool m_MoovIsBeforeMdat; +}; + +#endif // _AP4_FILE_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileByteStream.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileByteStream.h new file mode 100644 index 000000000..f7d82706e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileByteStream.h @@ -0,0 +1,112 @@ +/***************************************************************** +| +| AP4 - FileByteStream +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4ByteStream.h" +#include "Ap4Config.h" + +#ifndef _AP4_FILE_BYTE_STREAM_H_ +#define _AP4_FILE_BYTE_STREAM_H_ + +/*---------------------------------------------------------------------- +| AP4_FileByteStream ++---------------------------------------------------------------------*/ +class AP4_FileByteStream: public AP4_ByteStream +{ +public: + // types + typedef enum { + STREAM_MODE_READ = 0, + STREAM_MODE_WRITE = 1, + STREAM_MODE_READ_WRITE = 2 + } Mode; + + /** + * Create a stream from a file (opened or created). + * + * @param name Name of the file open or create + * @param mode Mode to use for the file + * @param stream Refrence to a pointer where the stream object will + * be returned + * @return AP4_SUCCESS if the file can be opened or created, or an error code if + * it cannot + */ + static AP4_Result Create(const char* name, Mode mode, AP4_ByteStream*& stream); + + // constructors + AP4_FileByteStream(AP4_ByteStream* delegate) : m_Delegate(delegate) {} + +#if !defined(AP4_CONFIG_NO_EXCEPTIONS) + /** + * @deprecated + */ + AP4_FileByteStream(const char* name, Mode mode); +#endif + + // AP4_ByteStream methods + AP4_Result ReadPartial(void* buffer, + AP4_Size bytesToRead, + AP4_Size& bytesRead) { + return m_Delegate->ReadPartial(buffer, bytesToRead, bytesRead); + } + AP4_Result WritePartial(const void* buffer, + AP4_Size bytesToWrite, + AP4_Size& bytesWritten) { + return m_Delegate->WritePartial(buffer, bytesToWrite, bytesWritten); + } + AP4_Result Seek(AP4_Position position) { return m_Delegate->Seek(position); } + AP4_Result Tell(AP4_Position& position) { return m_Delegate->Tell(position); } + AP4_Result GetSize(AP4_LargeSize& size) { return m_Delegate->GetSize(size); } + AP4_Result Flush() { return m_Delegate->Flush(); } + + // AP4_Referenceable methods + void AddReference() { m_Delegate->AddReference(); } + void Release() { m_Delegate->Release(); } + +protected: + // methods + virtual ~AP4_FileByteStream() { + delete m_Delegate; + } + + // members + AP4_ByteStream* m_Delegate; +}; + +#endif // _AP4_FILE_BYTE_STREAM_H_ + + + + + + + + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileCopier.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileCopier.cpp new file mode 100644 index 000000000..626763539 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileCopier.cpp @@ -0,0 +1,53 @@ +/***************************************************************** +| +| AP4 - File Copier +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4MoovAtom.h" +#include "Ap4FileCopier.h" +#include "Ap4Movie.h" +#include "Ap4File.h" +#include "Ap4FtypAtom.h" + +/*---------------------------------------------------------------------- +| AP4_FileCopier::Write ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FileCopier::Write(AP4_File& file, AP4_ByteStream& stream) +{ + // write the top-level atoms + for (AP4_List<AP4_Atom>::Item* item = file.GetTopLevelAtoms().FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* atom = item->GetData(); + atom->Write(stream); + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileCopier.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileCopier.h new file mode 100644 index 000000000..320177eaf --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileCopier.h @@ -0,0 +1,56 @@ +/***************************************************************** +| +| AP4 - File Writer +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_FILE_COPIER_H_ +#define _AP4_FILE_COPIER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_File; + +/*---------------------------------------------------------------------- +| AP4_FileCopier ++---------------------------------------------------------------------*/ +class AP4_FileCopier { +public: + // class methods + static AP4_Result Write(AP4_File& file, AP4_ByteStream& stream); + +private: + // don't instantiate this class + AP4_FileCopier() {}; +}; + +#endif // _AP4_FILE_COPIER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileWriter.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileWriter.cpp new file mode 100644 index 000000000..c7e8090cc --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileWriter.cpp @@ -0,0 +1,150 @@ +/***************************************************************** +| +| AP4 - File Writer +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4MoovAtom.h" +#include "Ap4FileWriter.h" +#include "Ap4Movie.h" +#include "Ap4File.h" +#include "Ap4TrakAtom.h" +#include "Ap4Track.h" +#include "Ap4Sample.h" +#include "Ap4DataBuffer.h" +#include "Ap4FtypAtom.h" +#include "Ap4SampleTable.h" + +/*---------------------------------------------------------------------- +| AP4_FileWriter::Write ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FileWriter::Write(AP4_File& file, AP4_ByteStream& stream, Interleaving /* interleaving */) +{ + // get the file type + AP4_FtypAtom* file_type = file.GetFileType(); + + // write the ftyp atom (always first) + if (file_type) file_type->Write(stream); + + // write the top-level atoms, except for ftyp, moov and mdat + for (AP4_List<AP4_Atom>::Item* atom_item = file.GetChildren().FirstItem(); + atom_item; + atom_item = atom_item->GetNext()) { + AP4_Atom* atom = atom_item->GetData(); + if (atom->GetType() != AP4_ATOM_TYPE_MDAT && + atom->GetType() != AP4_ATOM_TYPE_FTYP && + atom->GetType() != AP4_ATOM_TYPE_MOOV) { + atom->Write(stream); + } + } + + // get the movie object (and stop if there isn't any) + AP4_Movie* movie = file.GetMovie(); + if (movie == NULL) return AP4_SUCCESS; + + // see how much we've written so far + AP4_Position position; + stream.Tell(position); + + // backup and recompute all the chunk offsets + unsigned int t=0; + AP4_Result result = AP4_SUCCESS; + AP4_UI64 mdat_size = AP4_ATOM_HEADER_SIZE; + AP4_UI64 mdat_position = position+movie->GetMoovAtom()->GetSize(); + AP4_Array<AP4_Array<AP4_UI64>*> trak_chunk_offsets_backup; + AP4_Array<AP4_UI64> chunk_offsets; + for (AP4_List<AP4_Track>::Item* track_item = movie->GetTracks().FirstItem(); + track_item; + track_item = track_item->GetNext()) { + AP4_Track* track = track_item->GetData(); + AP4_TrakAtom* trak = track->GetTrakAtom(); + + // backup the chunk offsets + AP4_Array<AP4_UI64>* chunk_offsets_backup = new AP4_Array<AP4_UI64>(); + trak_chunk_offsets_backup.Append(chunk_offsets_backup); + result = trak->GetChunkOffsets(*chunk_offsets_backup); + if (AP4_FAILED(result)) goto end; + + // allocate space for the new chunk offsets + chunk_offsets.SetItemCount(chunk_offsets_backup->ItemCount()); + + // compute the new chunk offsets + AP4_Cardinal sample_count = track->GetSampleCount(); + AP4_SampleTable* sample_table = track->GetSampleTable(); + AP4_Sample sample; + for (AP4_Ordinal i=0; i<sample_count; i++) { + AP4_Ordinal chunk_index = 0; + AP4_Ordinal position_in_chunk = 0; + sample_table->GetSampleChunkPosition(i, chunk_index, position_in_chunk); + sample_table->GetSample(i, sample); + if (position_in_chunk == 0) { + // this sample is the first sample in a chunk, so this is the start of a chunk + if (chunk_index >= chunk_offsets.ItemCount()) return AP4_ERROR_INTERNAL; + chunk_offsets[chunk_index] = mdat_position+mdat_size; + } + mdat_size += sample.GetSize(); + } + result = trak->SetChunkOffsets(chunk_offsets); + } + + // write the moov atom + movie->GetMoovAtom()->Write(stream); + + // create and write the media data (mdat) + // FIXME: this only supports 32-bit mdat size + stream.WriteUI32((AP4_UI32)mdat_size); + stream.WriteUI32(AP4_ATOM_TYPE_MDAT); + + // write all tracks and restore the chunk offsets to their backed-up values + for (AP4_List<AP4_Track>::Item* track_item = movie->GetTracks().FirstItem(); + track_item; + track_item = track_item->GetNext(), ++t) { + AP4_Track* track = track_item->GetData(); + AP4_TrakAtom* trak = track->GetTrakAtom(); + + // restore the backed-up chunk offsets + result = trak->SetChunkOffsets(*trak_chunk_offsets_backup[t]); + + // write all the track's samples + AP4_Cardinal sample_count = track->GetSampleCount(); + AP4_Sample sample; + AP4_DataBuffer sample_data; + for (AP4_Ordinal i=0; i<sample_count; i++) { + track->ReadSample(i, sample, sample_data); + stream.Write(sample_data.GetData(), sample_data.GetDataSize()); + } + } + +end: + for (unsigned int i=0; i<trak_chunk_offsets_backup.ItemCount(); i++) { + delete trak_chunk_offsets_backup[i]; + } + + return result; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileWriter.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileWriter.h new file mode 100644 index 000000000..4c5c75391 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FileWriter.h @@ -0,0 +1,63 @@ +/***************************************************************** +| +| AP4 - File Writer +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_FILE_WRITER_H_ +#define _AP4_FILE_WRITER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_File; + +/*---------------------------------------------------------------------- +| AP4_FileWriter ++---------------------------------------------------------------------*/ +class AP4_FileWriter { +public: + // types + typedef enum { + INTERLEAVING_SEQUENTIAL + } Interleaving; + + // class methods + static AP4_Result Write(AP4_File& file, + AP4_ByteStream& stream, + Interleaving interleaving = INTERLEAVING_SEQUENTIAL); + +private: + // don't instantiate this class + AP4_FileWriter() {} +}; + +#endif // _AP4_FILE_WRITER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FragmentSampleTable.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FragmentSampleTable.cpp new file mode 100644 index 000000000..ce862f388 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FragmentSampleTable.cpp @@ -0,0 +1,299 @@ +/***************************************************************** +| +| AP4 - Fragment Based Sample Tables +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This atom is part of AP4 (MP4 Audio Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the atom COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4FragmentSampleTable.h" +#include "Ap4ByteStream.h" +#include "Ap4Sample.h" +#include "Ap4TrexAtom.h" +#include "Ap4TfhdAtom.h" +#include "Ap4ContainerAtom.h" +#include "Ap4TrunAtom.h" +#include "Ap4MovieFragment.h" + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::AP4_FragmentSampleTable ++---------------------------------------------------------------------*/ +AP4_FragmentSampleTable::AP4_FragmentSampleTable(AP4_ContainerAtom* traf, + AP4_TrexAtom* trex, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position mdat_payload_offset, + AP4_UI64 dts_origin) +{ + AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD)); + if (tfhd == NULL) return; + + // count all the samples and reserve space for them + unsigned int sample_count = 0; + for (AP4_List<AP4_Atom>::Item* item = traf->GetChildren().FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* atom = item->GetData(); + if (atom->GetType() == AP4_ATOM_TYPE_TRUN) { + AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, atom); + sample_count += trun->GetEntries().ItemCount(); + } + } + m_Samples.EnsureCapacity(sample_count); + + // process all the trun atoms + for (AP4_List<AP4_Atom>::Item* item = traf->GetChildren().FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* atom = item->GetData(); + if (atom->GetType() == AP4_ATOM_TYPE_TRUN) { + AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, atom); + AP4_Result result = AddTrun(trun, + tfhd, + trex, + sample_stream, + moof_offset, + mdat_payload_offset, + dts_origin); + if (AP4_FAILED(result)) return; + } + } +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::~AP4_FragmentSampleTable ++---------------------------------------------------------------------*/ +AP4_FragmentSampleTable::~AP4_FragmentSampleTable() +{ +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::AddTrun ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FragmentSampleTable::AddTrun(AP4_TrunAtom* trun, + AP4_TfhdAtom* tfhd, + AP4_TrexAtom* trex, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position& payload_offset, + AP4_UI64& dts_origin) +{ + AP4_Flags tfhd_flags = tfhd->GetFlags(); + AP4_Flags trun_flags = trun->GetFlags(); + + // update the number of samples + unsigned int start = m_Samples.ItemCount(); + m_Samples.SetItemCount(start + trun->GetEntries().ItemCount()); + + // base data offset + AP4_Position data_offset = 0; + if (tfhd_flags & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) { + data_offset = tfhd->GetBaseDataOffset(); + } else { + data_offset = moof_offset; + } + if (trun_flags & AP4_TRUN_FLAG_DATA_OFFSET_PRESENT) { + data_offset += trun->GetDataOffset(); + } + // MS hack + if (data_offset == moof_offset) { + data_offset = payload_offset; + } else { + payload_offset = data_offset; + } + + // sample description index + AP4_UI32 sample_description_index = 0; + if (tfhd_flags & AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT) { + sample_description_index = tfhd->GetSampleDescriptionIndex(); + } else if (trex) { + sample_description_index = trex->GetDefaultSampleDescriptionIndex(); + } + + // default sample size + AP4_UI32 default_sample_size = 0; + if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) { + default_sample_size = tfhd->GetDefaultSampleSize(); + } else if (trex) { + default_sample_size = trex->GetDefaultSampleSize(); + } + + // default sample duration + AP4_UI32 default_sample_duration = 0; + if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT) { + default_sample_duration = tfhd->GetDefaultSampleDuration(); + } else if (trex) { + default_sample_duration = trex->GetDefaultSampleDuration(); + } + + // default sample flags + AP4_UI32 default_sample_flags = 0; + if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT) { + default_sample_flags = tfhd->GetDefaultSampleFlags(); + } else if (trex) { + default_sample_flags = trex->GetDefaultSampleFlags(); + } + + // parse all trun entries to setup the samples + AP4_UI64 dts = dts_origin; + for (unsigned int i=0; i<trun->GetEntries().ItemCount(); i++) { + const AP4_TrunAtom::Entry& entry = trun->GetEntries()[i]; + AP4_Sample& sample = m_Samples[start+i]; + + // sample size + if (trun_flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) { + sample.SetSize(entry.sample_size); + } else { + sample.SetSize(default_sample_size); + } + payload_offset += sample.GetSize(); // update the payload offset + + // sample duration + if (trun_flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) { + sample.SetDuration(entry.sample_duration); + } else { + sample.SetDuration(default_sample_duration); + } + + // sample flags + AP4_UI32 sample_flags = default_sample_flags; + if (i==0 && (trun_flags & AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT)) { + sample_flags = trun->GetFirstSampleFlags(); + } else if (trun_flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) { + sample_flags = entry.sample_flags; + } + if ((sample_flags & AP4_FRAG_FLAG_SAMPLE_IS_DIFFERENCE) == 0) { + sample.SetSync(true); + } else { + sample.SetSync(false); + } + + // sample description index + sample.SetDescriptionIndex(sample_description_index); + + // data stream + if (sample_stream) sample.SetDataStream(*sample_stream); + + // data offset + sample.SetOffset(data_offset); + data_offset += sample.GetSize(); + + // dts and cts + sample.SetDts(dts); + if (trun_flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) { + sample.SetCts(dts+entry.sample_composition_time_offset); + } else { + sample.SetCts(dts); + } + + // update the counters + dts += sample.GetDuration(); + m_Duration += sample.GetDuration(); + } + + // update the dts + dts_origin = dts; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::GetSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FragmentSampleTable::GetSample(AP4_Ordinal index, + AP4_Sample& sample) +{ + if (index >= m_Samples.ItemCount()) return AP4_ERROR_OUT_OF_RANGE; + + // copy the sample + sample = m_Samples[index]; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::GetSampleCount ++---------------------------------------------------------------------*/ +AP4_Cardinal +AP4_FragmentSampleTable::GetSampleCount() +{ + return m_Samples.ItemCount(); +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::GetSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_FragmentSampleTable::GetSampleDescription(AP4_Ordinal /*index*/) +{ + return NULL; // FIXME +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::GetSampleDescriptionCount ++---------------------------------------------------------------------*/ +AP4_Cardinal +AP4_FragmentSampleTable::GetSampleDescriptionCount() +{ + return 1; // FIXME +} + +/*---------------------------------------------------------------------- +| AP4_AtomSampleTable::GetSampleChunkPosition ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FragmentSampleTable::GetSampleChunkPosition(AP4_Ordinal sample_index, + AP4_Ordinal& chunk_index, + AP4_Ordinal& position_in_chunk) +{ + chunk_index = 0; + position_in_chunk = sample_index; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::GetSampleIndexForTimeStamp ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FragmentSampleTable::GetSampleIndexForTimeStamp(AP4_UI64 /*ts*/, + AP4_Ordinal& sample_index) +{ + sample_index = 0; // FIXME + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable::GetNearestSyncSampleIndex ++---------------------------------------------------------------------*/ +AP4_Ordinal +AP4_FragmentSampleTable::GetNearestSyncSampleIndex(AP4_Ordinal /*sample_index*/, bool /*before*/) +{ + return 0; // FIXME +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FragmentSampleTable.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FragmentSampleTable.h new file mode 100644 index 000000000..0c626bcb5 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FragmentSampleTable.h @@ -0,0 +1,94 @@ +/***************************************************************** +| +| AP4 - Fragment Based Sample Table +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This atom is part of AP4 (MP4 Audio Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the atom COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_FRAGMENT_SAMPLE_TABLE_H_ +#define _AP4_FRAGMENT_SAMPLE_TABLE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4SampleTable.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| forward declarations ++---------------------------------------------------------------------*/ +class AP4_Atom; +class AP4_ByteStream; +class AP4_TrunAtom; +class AP4_TrexAtom; +class AP4_TfhdAtom; + +/*---------------------------------------------------------------------- +| AP4_FragmentSampleTable ++---------------------------------------------------------------------*/ +class AP4_FragmentSampleTable : public AP4_SampleTable +{ + public: + // methods + AP4_FragmentSampleTable(AP4_ContainerAtom* traf, + AP4_TrexAtom* trex, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec correctly + AP4_UI64 dts_origin=0); + virtual ~AP4_FragmentSampleTable(); + + // AP4_SampleTable methods + virtual AP4_Result GetSample(AP4_Ordinal sample_index, AP4_Sample& sample); + virtual AP4_Cardinal GetSampleCount(); + virtual AP4_SampleDescription* GetSampleDescription(AP4_Ordinal sd_index); + virtual AP4_Cardinal GetSampleDescriptionCount(); + virtual AP4_Result GetSampleChunkPosition(AP4_Ordinal sample_index, + AP4_Ordinal& chunk_index, + AP4_Ordinal& position_in_chunk); + virtual AP4_Result GetSampleIndexForTimeStamp(AP4_UI64 ts, AP4_Ordinal& sample_index); + virtual AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal index, bool before=true); + + // methods + AP4_UI64 GetDuration() { return m_Duration; } + +private: + // members + AP4_TrunAtom* m_TrunAtom; + AP4_Array<AP4_Sample> m_Samples; + AP4_UI64 m_Duration; + + // methods + AP4_Result AddTrun(AP4_TrunAtom* trun, + AP4_TfhdAtom* tfhd, + AP4_TrexAtom* trex, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position& payload_offset, + AP4_UI64& dts_origin); + +}; + +#endif // _AP4_FRAGMENT_SAMPLE_TABLE_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FrmaAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FrmaAtom.cpp new file mode 100644 index 000000000..cfaef69b3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FrmaAtom.cpp @@ -0,0 +1,75 @@ +/***************************************************************** +| +| AP4 - frma Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4FrmaAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_FrmaAtom::AP4_FrmaAtom ++---------------------------------------------------------------------*/ +AP4_FrmaAtom::AP4_FrmaAtom(AP4_UI32 original_format) : + AP4_Atom(AP4_ATOM_TYPE_FRMA, AP4_ATOM_HEADER_SIZE+4), + m_OriginalFormat(original_format) +{ +} + +/*---------------------------------------------------------------------- +| AP4_FrmaAtom::AP4_FrmaAtom ++---------------------------------------------------------------------*/ +AP4_FrmaAtom::AP4_FrmaAtom(AP4_UI32 size, AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_FRMA, size) +{ + stream.ReadUI32(m_OriginalFormat); +} + +/*---------------------------------------------------------------------- +| AP4_FrmaAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FrmaAtom::WriteFields(AP4_ByteStream& stream) +{ + // write the original format + return stream.WriteUI32(m_OriginalFormat); +} + +/*---------------------------------------------------------------------- +| AP4_FrmaAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FrmaAtom::InspectFields(AP4_AtomInspector& inspector) +{ + char format[5]; + AP4_FormatFourChars(format, m_OriginalFormat); + inspector.AddField("original_format", format); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FrmaAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FrmaAtom.h new file mode 100644 index 000000000..c6ea77a08 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FrmaAtom.h @@ -0,0 +1,70 @@ +/***************************************************************** +| +| AP4 - frma Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_FRMA_ATOM_H_ +#define _AP4_FRMA_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_FrmaAtom ++---------------------------------------------------------------------*/ +class AP4_FrmaAtom : public AP4_Atom +{ +public: + // class methods + static AP4_FrmaAtom* Create(AP4_Size size, AP4_ByteStream& stream) { + return new AP4_FrmaAtom(size, stream); + } + + // constructors + AP4_FrmaAtom(AP4_UI32 original_format); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + AP4_UI32 GetOriginalFormat() { return m_OriginalFormat; } + +private: + // methods + AP4_FrmaAtom(AP4_UI32 size, AP4_ByteStream& stream); + + // members + AP4_UI32 m_OriginalFormat; +}; + +#endif // _AP4_FRMA_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtabAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtabAtom.cpp new file mode 100644 index 000000000..287238ebd --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtabAtom.cpp @@ -0,0 +1,64 @@ +/*****************************************************************
+|
+| AP4 - ftab Atom
+|
+| Copyright 2002 Gilles Boccon-Gibod & Julien Boeuf
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+
+#include "Ap4FtabAtom.h"
+
+/*----------------------------------------------------------------------
+| AP4_FtabAtom::AP4_FtabAtom
++---------------------------------------------------------------------*/
+
+AP4_FtabAtom::AP4_FtabAtom(AP4_Size size,
+ AP4_ByteStream& stream)
+ : AP4_Atom(AP4_ATOM_TYPE_FTAB)
+{
+ AP4_UI16 entryCount;
+ stream.ReadUI16(entryCount);
+
+ m_FontRecords.EnsureCapacity(entryCount);
+
+ while(entryCount--)
+ {
+ AP4_Tx3gFontRecord fontRecord;
+
+ stream.ReadUI16(fontRecord.Id);
+
+ AP4_UI08 len;
+ stream.ReadUI08(len);
+
+ char buff[256];
+ stream.ReadString(buff, len+1);
+
+ fontRecord.Name = buff;
+
+ m_FontRecords.Append(fontRecord);
+ }
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtabAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtabAtom.h new file mode 100644 index 000000000..0845347d5 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtabAtom.h @@ -0,0 +1,78 @@ +/*****************************************************************
+|
+| AP4 - ftab Atom
+|
+| Copyright 2002 Gilles Boccon-Gibod & Julien Boeuf
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_FTAB_ATOM_H_
+#define _AP4_FTAB_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+#include "Ap4Types.h"
+#include "Ap4Array.h"
+
+/*----------------------------------------------------------------------
+| AP4_FtabAtom
++---------------------------------------------------------------------*/
+class AP4_FtabAtom : public AP4_Atom
+{
+public:
+ AP4_FtabAtom(AP4_Size size,
+ AP4_ByteStream& stream);
+
+ AP4_Result WriteFields(AP4_ByteStream& stream) { return AP4_FAILURE; }
+
+ struct AP4_Tx3gFontRecord
+ {
+ AP4_UI16 Id;
+ AP4_String Name;
+ };
+
+ AP4_Array<AP4_Tx3gFontRecord>& GetFontRecords() { return m_FontRecords; }
+
+ AP4_Result LookupFont(AP4_UI16 Id, AP4_String& Name)
+ {
+ for(unsigned long i = 0; i < m_FontRecords.ItemCount(); i++)
+ {
+ if(m_FontRecords[i].Id == Id)
+ {
+ Name = m_FontRecords[i].Name;
+ return AP4_SUCCESS;
+ }
+ }
+
+ return AP4_FAILURE;
+ }
+
+private:
+
+ // members
+ AP4_Array<AP4_Tx3gFontRecord> m_FontRecords;
+};
+
+#endif // _AP4_FTAB_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtypAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtypAtom.cpp new file mode 100644 index 000000000..8bd20f0cc --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtypAtom.cpp @@ -0,0 +1,130 @@ +/***************************************************************** +| +| AP4 - ftyp Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4FtypAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_FtypAtom) + +/*---------------------------------------------------------------------- +| AP4_FtypAtom::AP4_FtypAtom ++---------------------------------------------------------------------*/ +AP4_FtypAtom::AP4_FtypAtom(AP4_UI32 size, AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_FTYP, size) +{ + stream.ReadUI32(m_MajorBrand); + stream.ReadUI32(m_MinorVersion); + size -= 16; + while (size) { + AP4_UI32 compatible_brand; + stream.ReadUI32(compatible_brand); + m_CompatibleBrands.Append(compatible_brand); + size -= 4; + } +} + +/*---------------------------------------------------------------------- +| AP4_FtypAtom::AP4_FtypAtom ++---------------------------------------------------------------------*/ +AP4_FtypAtom::AP4_FtypAtom(AP4_UI32 major_brand, + AP4_UI32 minor_version, + AP4_UI32* compatible_brands, + AP4_Cardinal compatible_brand_count) : + AP4_Atom(AP4_ATOM_TYPE_FTYP, AP4_ATOM_HEADER_SIZE+8+4*compatible_brand_count), + m_MajorBrand(major_brand), + m_MinorVersion(minor_version), + m_CompatibleBrands(compatible_brands, compatible_brand_count) +{ +} + +/*---------------------------------------------------------------------- +| AP4_FtypAtom::HasCompatibleBrand ++---------------------------------------------------------------------*/ +bool +AP4_FtypAtom::HasCompatibleBrand(AP4_UI32 brand) +{ + for (unsigned int i=0; i<m_CompatibleBrands.ItemCount(); i++) { + if (m_CompatibleBrands[i] == brand) return true; + } + + return false; +} + +/*---------------------------------------------------------------------- +| AP4_FtypAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FtypAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // major brand + result = stream.WriteUI32(m_MajorBrand); + if (AP4_FAILED(result)) return result; + + // minor version + result = stream.WriteUI32(m_MinorVersion); + if (AP4_FAILED(result)) return result; + + // compatible brands + AP4_Cardinal compat_brand_count = m_CompatibleBrands.ItemCount(); + for (AP4_Ordinal i=0; i<compat_brand_count; i++) { + result = stream.WriteUI32(m_CompatibleBrands[i]); + if (AP4_FAILED(result)) return result; + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_FtypAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_FtypAtom::InspectFields(AP4_AtomInspector& inspector) +{ + char name[5]; + AP4_FormatFourChars(name, m_MajorBrand); + inspector.AddField("major_brand", name); + inspector.AddField("minor_version", m_MinorVersion, AP4_AtomInspector::HINT_HEX); + + // compatible brands + for (unsigned int i=0; i<m_CompatibleBrands.ItemCount(); i++) { + AP4_UI32 cb = m_CompatibleBrands[i]; + AP4_FormatFourChars(name, cb); + inspector.AddField("compatible_brand", name); + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtypAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtypAtom.h new file mode 100644 index 000000000..fe6e2c0f4 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4FtypAtom.h @@ -0,0 +1,88 @@ +/***************************************************************** +| +| AP4 - ftyp Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_FTYP_ATOM_H_ +#define _AP4_FTYP_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_FTYP_BRAND_ISOM = AP4_ATOM_TYPE('i','s','o','m'); + +/*---------------------------------------------------------------------- +| AP4_FtypAtom ++---------------------------------------------------------------------*/ +class AP4_FtypAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_FtypAtom, AP4_Atom) + + // class methods + static AP4_FtypAtom* Create(AP4_Size size, AP4_ByteStream& stream) { + return new AP4_FtypAtom(size, stream); + } + + // methods + AP4_FtypAtom(AP4_UI32 major_brand, + AP4_UI32 minor_version, + AP4_UI32* compatible_brands = NULL, + AP4_Cardinal compatible_brand_count = 0); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetMajorBrand() { return m_MajorBrand; } + AP4_UI32 GetMinorVersion() { return m_MinorVersion; } + AP4_Array<AP4_UI32>& GetCompatibleBrands() { + return m_CompatibleBrands; + } + bool HasCompatibleBrand(AP4_UI32 brand); + +private: + // methods + AP4_FtypAtom(AP4_UI32 size, AP4_ByteStream& stream); + + // members + AP4_UI32 m_MajorBrand; + AP4_UI32 m_MinorVersion; + AP4_Array<AP4_UI32> m_CompatibleBrands; +}; + +#endif // _AP4_FTYP_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4GrpiAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4GrpiAtom.cpp new file mode 100644 index 000000000..f75764a14 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4GrpiAtom.cpp @@ -0,0 +1,137 @@ +/***************************************************************** +| +| AP4 - ohdr Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4GrpiAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_GrpiAtom) + +/*---------------------------------------------------------------------- +| AP4_GrpiAtom::Create ++---------------------------------------------------------------------*/ +AP4_GrpiAtom* +AP4_GrpiAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_GrpiAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_GrpiAtom::AP4_GrpiAtom ++---------------------------------------------------------------------*/ +AP4_GrpiAtom::AP4_GrpiAtom(AP4_UI08 key_encryption_method, + const char* group_id, + const AP4_UI08* group_key, + AP4_Size group_key_length) : + AP4_Atom(AP4_ATOM_TYPE_GRPI, AP4_FULL_ATOM_HEADER_SIZE, 0, 0), + m_KeyEncryptionMethod(key_encryption_method), + m_GroupId(group_id), + m_GroupKey(group_key, group_key_length) +{ + m_Size32 += 2+1+2+m_GroupId.GetLength()+group_key_length; +} + +/*---------------------------------------------------------------------- +| AP4_GrpiAtom::AP4_GrpiAtom ++---------------------------------------------------------------------*/ +AP4_GrpiAtom::AP4_GrpiAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_GRPI, size, false, version, flags) +{ + // group id length + AP4_UI16 group_id_length = 0; + stream.ReadUI16(group_id_length); + + // encryption method + stream.ReadUI08(m_KeyEncryptionMethod); + + // group key length + AP4_UI16 group_key_length = 0; + stream.ReadUI16(group_key_length); + + // group id + char* group_id = new char[group_id_length]; + stream.Read(group_id, group_id_length); + m_GroupId.Assign(group_id, group_id_length); + delete[] group_id; + + // group key + m_GroupKey.SetDataSize(group_key_length); + stream.Read(m_GroupKey.UseData(), group_key_length); +} + +/*---------------------------------------------------------------------- +| AP4_GrpiAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_GrpiAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_CHECK(stream.WriteUI16((AP4_UI16)m_GroupId.GetLength())); + AP4_CHECK(stream.WriteUI08(m_KeyEncryptionMethod)); + AP4_CHECK(stream.WriteUI16((AP4_UI16)m_GroupKey.GetDataSize())); + AP4_CHECK(stream.Write(m_GroupId.GetChars(), m_GroupId.GetLength())); + AP4_CHECK(stream.Write(m_GroupKey.GetData(), m_GroupKey.GetDataSize())); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_GrpiAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_GrpiAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("key encryption method", m_KeyEncryptionMethod); + inspector.AddField("group id", m_GroupId.GetChars()); + inspector.AddField("group key", m_GroupKey.GetData(), + m_GroupKey.GetDataSize()); + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_GrpiAtom::Clone ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_GrpiAtom::Clone() +{ + return new AP4_GrpiAtom(m_KeyEncryptionMethod, + m_GroupId.GetChars(), + m_GroupKey.GetData(), + m_GroupKey.GetDataSize()); +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4GrpiAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4GrpiAtom.h new file mode 100644 index 000000000..80aeae6c2 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4GrpiAtom.h @@ -0,0 +1,82 @@ +/***************************************************************** +| +| AP4 - grpi Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_GRPI_ATOM_H_ +#define _AP4_GRPI_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4String.h" +#include "Ap4DataBuffer.h" + +/*---------------------------------------------------------------------- +| AP4_GrpiAtom ++---------------------------------------------------------------------*/ +class AP4_GrpiAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_GrpiAtom, AP4_Atom) + + // class methods + static AP4_GrpiAtom* Create(AP4_Size size, + AP4_ByteStream& stream); + + // constructor + AP4_GrpiAtom(AP4_UI08 key_encryption_method, + const char* group_id, + const AP4_UI08* group_key, + AP4_Size group_key_length); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Atom* Clone(); + + // accessors + AP4_UI08 GetKeyEncryptionMethod() const { return m_KeyEncryptionMethod; } + void SetKeyEncryptionMethod(AP4_UI08 encryption_method) { m_KeyEncryptionMethod = encryption_method; } + const AP4_String& GetGroupId() const { return m_GroupId; } + const AP4_DataBuffer& GetGroupKey() const { return m_GroupKey; } + +private: + // methods + AP4_GrpiAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI08 m_KeyEncryptionMethod; + AP4_String m_GroupId; + AP4_DataBuffer m_GroupKey; +}; + +#endif // _AP4_GRPI_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HdlrAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HdlrAtom.cpp new file mode 100644 index 000000000..9a25e3ed3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HdlrAtom.cpp @@ -0,0 +1,146 @@ +/***************************************************************** +| +| AP4 - hdlr Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4HdlrAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_HdlrAtom) + +/*---------------------------------------------------------------------- +| AP4_HdlrAtom::Create ++---------------------------------------------------------------------*/ +AP4_HdlrAtom* +AP4_HdlrAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_HdlrAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_HdlrAtom::AP4_HdlrAtom ++---------------------------------------------------------------------*/ +AP4_HdlrAtom::AP4_HdlrAtom(AP4_Atom::Type hdlr_type, const char* hdlr_name) : + AP4_Atom(AP4_ATOM_TYPE_HDLR, AP4_FULL_ATOM_HEADER_SIZE, 0, 0), + m_HandlerType(hdlr_type), + m_HandlerName(hdlr_name) +{ + m_Size32 += 20+m_HandlerName.GetLength()+1; + m_Reserved[0] = m_Reserved[1] = m_Reserved[2] = 0; +} + +/*---------------------------------------------------------------------- +| AP4_HdlrAtom::AP4_HdlrAtom ++---------------------------------------------------------------------*/ +AP4_HdlrAtom::AP4_HdlrAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_HDLR, size, version, flags) +{ + AP4_UI32 predefined; + stream.ReadUI32(predefined); + stream.ReadUI32(m_HandlerType); + stream.ReadUI32(m_Reserved[0]); + stream.ReadUI32(m_Reserved[1]); + stream.ReadUI32(m_Reserved[2]); + + // read the name unless it is empty + int name_size = size-(AP4_FULL_ATOM_HEADER_SIZE+20); + if (name_size == 0) return; + char* name = new char[name_size+1]; + stream.Read(name, name_size); + name[name_size] = '\0'; // force a null termination + // handle a special case: the Quicktime files have a pascal + // string here, but ISO MP4 files have a C string. + // we try to detect a pascal encoding and correct it. + if (name[0] == name_size-1) { + m_HandlerName = name+1; + } else { + m_HandlerName = name; + } + delete[] name; +} + +/*---------------------------------------------------------------------- +| AP4_HdlrAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HdlrAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the data + result = stream.WriteUI32(0); // predefined + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_HandlerType); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_Reserved[0]); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_Reserved[1]); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_Reserved[2]); + if (AP4_FAILED(result)) return result; + AP4_UI08 name_size = (AP4_UI08)m_HandlerName.GetLength(); + if (AP4_FULL_ATOM_HEADER_SIZE+20+name_size > m_Size32) { + name_size = m_Size32-AP4_FULL_ATOM_HEADER_SIZE+20; + } + if (name_size) { + result = stream.Write(m_HandlerName.GetChars(), name_size); + if (AP4_FAILED(result)) return result; + } + + // pad with zeros if necessary + AP4_Size padding = m_Size32-(AP4_FULL_ATOM_HEADER_SIZE+20+name_size); + while (padding--) stream.WriteUI08(0); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HdlrAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HdlrAtom::InspectFields(AP4_AtomInspector& inspector) +{ + char type[5]; + AP4_FormatFourChars(type, m_HandlerType); + inspector.AddField("handler_type", type); + inspector.AddField("handler_name", m_HandlerName.GetChars()); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HdlrAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HdlrAtom.h new file mode 100644 index 000000000..c5b1bf135 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HdlrAtom.h @@ -0,0 +1,91 @@ +/***************************************************************** +| +| AP4 - hdlr Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_HDLR_ATOM_H_ +#define _AP4_HDLR_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_HANDLER_TYPE_SOUN = AP4_ATOM_TYPE('s','o','u','n'); +const AP4_UI32 AP4_HANDLER_TYPE_VIDE = AP4_ATOM_TYPE('v','i','d','e'); +const AP4_UI32 AP4_HANDLER_TYPE_HINT = AP4_ATOM_TYPE('h','i','n','t'); +const AP4_UI32 AP4_HANDLER_TYPE_MDIR = AP4_ATOM_TYPE('m','d','i','r'); +const AP4_UI32 AP4_HANDLER_TYPE_TEXT = AP4_ATOM_TYPE('t','e','x','t'); +const AP4_UI32 AP4_HANDLER_TYPE_TX3G = AP4_ATOM_TYPE('t','x','3','g'); +const AP4_UI32 AP4_HANDLER_TYPE_JPEG = AP4_ATOM_TYPE('j','p','e','g'); +const AP4_UI32 AP4_HANDLER_TYPE_ODSM = AP4_ATOM_TYPE('o','d','s','m'); +const AP4_UI32 AP4_HANDLER_TYPE_SDSM = AP4_ATOM_TYPE('s','d','s','m'); +// ==> Start patch MPC +const AP4_UI32 AP4_HANDLER_TYPE_SUBP = AP4_ATOM_TYPE('s','u','b','p'); +// <== End patch MPC + +/*---------------------------------------------------------------------- +| AP4_HdlrAtom ++---------------------------------------------------------------------*/ +class AP4_HdlrAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_HdlrAtom, AP4_Atom) + + // class methods + static AP4_HdlrAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_HdlrAtom(AP4_UI32 hdlr_type, const char* hdlr_name); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + AP4_UI32 GetHandlerType() { return m_HandlerType; } + AP4_String GetHandlerName() { return m_HandlerName; } + +private: + // methods + AP4_HdlrAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI32 m_HandlerType; + AP4_UI32 m_Reserved[3]; + AP4_String m_HandlerName; +}; + +#endif // _AP4_HDLR_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HintTrackReader.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HintTrackReader.cpp new file mode 100644 index 000000000..3e35131cb --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HintTrackReader.cpp @@ -0,0 +1,341 @@ +/***************************************************************** +| +| AP4 - Hint Track Reader +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include <stdlib.h> +#include <time.h> +#include "Ap4HintTrackReader.h" +#include "Ap4DataBuffer.h" +#include "Ap4Track.h" +#include "Ap4Movie.h" +#include "Ap4SdpAtom.h" +#include "Ap4RtpHint.h" +#include "Ap4TrakAtom.h" +#include "Ap4TrefTypeAtom.h" +#include "Ap4TimsAtom.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::AP4_HintTrackReader ++---------------------------------------------------------------------*/ +AP4_HintTrackReader::AP4_HintTrackReader(AP4_Track& hint_track, + AP4_Movie& movie, + AP4_UI32 ssrc) : + m_HintTrack(hint_track), + m_MediaTrack(NULL), + m_MediaTimeScale(0), + m_RtpSampleData(NULL), + m_Ssrc(ssrc), + m_SampleIndex(0), + m_PacketIndex(0), + m_RtpSequenceStart(0), + m_RtpTimeStampStart(0), + m_RtpTimeScale(0) +{ + // get the media track + AP4_TrakAtom* hint_trak_atom = hint_track.GetTrakAtom(); + AP4_Atom* atom = hint_trak_atom->FindChild("tref/hint"); + if (atom != NULL) { + AP4_UI32 media_track_id = ((AP4_TrefTypeAtom*) atom)->GetTrackIds()[0]; + m_MediaTrack = movie.GetTrack(media_track_id); + + // get the media time scale + m_MediaTimeScale = m_MediaTrack->GetMediaTimeScale(); + } + + // initiate random generator + srand((int)time(NULL)); + + // rtp sequence start init TODO!! + m_RtpSequenceStart = rand(); + + // rtp timestamp start init TODO!! + m_RtpTimeStampStart = rand(); + + // rtp time scale + atom = hint_trak_atom->FindChild("mdia/minf/stbl/rtp /tims"); + if (atom) { + AP4_TimsAtom* tims = (AP4_TimsAtom*)atom; + m_RtpTimeScale = tims->GetTimeScale(); + } + + // generate a random ssrc if = 0 + if (m_Ssrc == 0) { + m_Ssrc = rand(); + } + + // get the first sample + GetRtpSample(0); +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::Create ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::Create(AP4_Track& hint_track, + AP4_Movie& movie, + AP4_UI32 ssrc, + AP4_HintTrackReader*& reader) +{ + // default value + reader = NULL; + + // check the type + if (hint_track.GetType() != AP4_Track::TYPE_HINT) { + return AP4_ERROR_INVALID_TRACK_TYPE; + } + + // create a new object + reader = new AP4_HintTrackReader(hint_track, movie, ssrc); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::~AP4_HintTrackReader ++---------------------------------------------------------------------*/ +AP4_HintTrackReader::~AP4_HintTrackReader() +{ + delete m_RtpSampleData; +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::GetRtpSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::GetRtpSample(AP4_Ordinal index) +{ + // get the sample + AP4_Result result = m_HintTrack.GetSample(index, m_CurrentHintSample); + if (AP4_FAILED(result)) return result; + + // renew the sample data + delete m_RtpSampleData; + AP4_ByteStream& rtp_data_stream = *m_CurrentHintSample.GetDataStream(); + rtp_data_stream.Seek(m_CurrentHintSample.GetOffset()); + m_RtpSampleData = new AP4_RtpSampleData(rtp_data_stream, + m_CurrentHintSample.GetSize()); + + // reinit the packet index + m_PacketIndex = 0; + + // release the stream + rtp_data_stream.Release(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::GetCurrentTimeStampMs ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_HintTrackReader::GetCurrentTimeStampMs() +{ + return (AP4_UI32)AP4_ConvertTime(m_CurrentHintSample.GetCts(), + m_HintTrack.GetMediaTimeScale(), + 1000); +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::Rewind ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::Rewind() +{ + m_SampleIndex = 0; + return GetRtpSample(m_SampleIndex); +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::GetSdpText ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::GetSdpText(AP4_String& sdp_text) +{ + AP4_Atom* sdp_atom = m_HintTrack.GetTrakAtom()->FindChild("udta/hnti/sdp "); + if (sdp_atom == NULL) return AP4_FAILURE; + + // C cast is OK because we know the type of the atom + sdp_text = ((AP4_SdpAtom*) sdp_atom)->GetSdpText(); + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::SeekToTimeStampMs ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::SeekToTimeStampMs(AP4_UI32 desired_ts_ms, + AP4_UI32& actual_ts_ms) +{ + // get the sample index + AP4_Cardinal index; + AP4_Result result = m_HintTrack.GetSampleIndexForTimeStampMs(desired_ts_ms, index); + if (AP4_FAILED(result)) return result; + + // get the current sample based on the index and renew the sample data + result = GetRtpSample(index); + if (AP4_FAILED(result)) return result; + + // set the actual ts + actual_ts_ms = GetCurrentTimeStampMs(); + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::GetNextPacket ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::GetNextPacket(AP4_DataBuffer& packet_data, + AP4_UI32& ts_ms) +{ + AP4_Result result = AP4_SUCCESS; + + // get the next rtp sample if needed + AP4_List<AP4_RtpPacket>* packets = &m_RtpSampleData->GetPackets(); + while (m_PacketIndex == packets->ItemCount()) { // while: handle the 0 packet case + result = GetRtpSample(++m_SampleIndex); + if (AP4_FAILED(result)) return result; + packets = &m_RtpSampleData->GetPackets(); + } + + // get the packet + AP4_RtpPacket* packet; + result = packets->Get(m_PacketIndex++, packet); + if (AP4_FAILED(result)) return result; + + // build it + result = BuildRtpPacket(packet, packet_data); + if (AP4_FAILED(result)) return result; + + // set the time stamp + ts_ms = GetCurrentTimeStampMs(); + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::BuildRtpPacket ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::BuildRtpPacket(AP4_RtpPacket* packet, + AP4_DataBuffer& packet_data) +{ + // set the data size + AP4_Result result = packet_data.SetDataSize(packet->GetConstructedDataSize()); + if (AP4_FAILED(result)) return result; + + // now write + AP4_ByteStream* stream = new AP4_MemoryByteStream(packet_data); + + // header + ssrc + stream->WriteUI08(0x80 | (packet->GetPBit() << 5) | (packet->GetXBit() << 4)); + stream->WriteUI08((packet->GetMBit() << 7) | packet->GetPayloadType()); + stream->WriteUI16(m_RtpSequenceStart + packet->GetSequenceSeed()); + stream->WriteUI32(m_RtpTimeStampStart + (AP4_UI32)m_CurrentHintSample.GetCts() + packet->GetTimeStampOffset()); + stream->WriteUI32(m_Ssrc); + + AP4_List<AP4_RtpConstructor>::Item* constructors_it + = packet->GetConstructors().FirstItem(); + while (constructors_it != NULL) { + AP4_RtpConstructor* constructor = constructors_it->GetData(); + + // add data to the packet according to the constructor + switch (constructor->GetType()) { + case AP4_RTP_CONSTRUCTOR_TYPE_NOOP: + // nothing to do here + break; + case AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE: + result = WriteImmediateRtpData( + (AP4_ImmediateRtpConstructor*) constructor, stream); + if (AP4_FAILED(result)) return result; + break; + case AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE: + result = WriteSampleRtpData( + (AP4_SampleRtpConstructor*) constructor, stream); + if (AP4_FAILED(result)) return result; + break; + case AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC: + return AP4_ERROR_NOT_SUPPORTED; + default: + // unknown constructor type + return AP4_FAILURE; + } + + // iterate + constructors_it = constructors_it->GetNext(); + } + + // release the stream + stream->Release(); + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::WriteImmediateRtpData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::WriteImmediateRtpData(AP4_ImmediateRtpConstructor* constructor, + AP4_ByteStream* data_stream) +{ + const AP4_DataBuffer& data_buffer = constructor->GetData(); + return data_stream->Write(data_buffer.GetData(), data_buffer.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader::WriteSampleRtpData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HintTrackReader::WriteSampleRtpData(AP4_SampleRtpConstructor* constructor, + AP4_ByteStream* data_stream) +{ + AP4_Track* referenced_track = NULL; + if (constructor->GetTrackRefIndex() == 0xFF) { + // data is in the hint track + referenced_track = &m_HintTrack; + } else { + // check if we have a media track + if (m_MediaTrack == NULL) return AP4_FAILURE; + referenced_track = m_MediaTrack; + } + + // write the sample data + AP4_Sample sample; + AP4_Result result = referenced_track->GetSample(constructor->GetSampleNum()-1, // adjust + sample); + AP4_DataBuffer buffer(constructor->GetLength()); + result = sample.ReadData( + buffer, constructor->GetLength(), constructor->GetSampleOffset()); + if (AP4_FAILED(result)) return result; + + // write the data + return data_stream->Write(buffer.GetData(), buffer.GetDataSize()); +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HintTrackReader.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HintTrackReader.h new file mode 100644 index 000000000..71b2aebaa --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HintTrackReader.h @@ -0,0 +1,102 @@ +/***************************************************************** +| +| AP4 - Hint Track Reader +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_HINT_TRACK_READER_H_ +#define _AP4_HINT_TRACK_READER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Sample.h" + +/*---------------------------------------------------------------------- +| class declarations ++---------------------------------------------------------------------*/ +class AP4_DataBuffer; +class AP4_Movie; +class AP4_Track; +class AP4_RtpSampleData; +class AP4_RtpPacket; +class AP4_ImmediateRtpConstructor; +class AP4_SampleRtpConstructor; +class AP4_String; + +/*---------------------------------------------------------------------- +| AP4_HintTrackReader ++---------------------------------------------------------------------*/ +class AP4_HintTrackReader +{ +public: + // constructor and destructor + static AP4_Result Create(AP4_Track& hint_track, + AP4_Movie& movie, + AP4_UI32 ssrc, // if 0, a random value is chosen + AP4_HintTrackReader*& reader); + ~AP4_HintTrackReader(); + + // methods + AP4_Result GetNextPacket(AP4_DataBuffer& packet, + AP4_UI32& ts_ms); + AP4_Result SeekToTimeStampMs(AP4_UI32 desired_ts_ms, + AP4_UI32& actual_ts_ms); + AP4_UI32 GetCurrentTimeStampMs(); + AP4_Result Rewind(); + AP4_Result GetSdpText(AP4_String& sdp); + AP4_Track* GetMediaTrack() { return m_MediaTrack; } + +private: + // use the factory instead of the constructor + AP4_HintTrackReader(AP4_Track& hint_track, + AP4_Movie& movie, + AP4_UI32 ssrc); + + // methods + AP4_Result GetRtpSample(AP4_Ordinal index); + AP4_Result BuildRtpPacket(AP4_RtpPacket* packet, + AP4_DataBuffer& packet_data); + AP4_Result WriteImmediateRtpData(AP4_ImmediateRtpConstructor* constructor, + AP4_ByteStream* data_stream); + AP4_Result WriteSampleRtpData(AP4_SampleRtpConstructor* constructor, + AP4_ByteStream* data_stream); + + // members + AP4_Track& m_HintTrack; + AP4_Track* m_MediaTrack; + AP4_UI32 m_MediaTimeScale; + AP4_Sample m_CurrentHintSample; + AP4_RtpSampleData* m_RtpSampleData; + AP4_UI32 m_Ssrc; + AP4_Ordinal m_SampleIndex; + AP4_Ordinal m_PacketIndex; + AP4_UI16 m_RtpSequenceStart; + AP4_UI32 m_RtpTimeStampStart; + AP4_UI32 m_RtpTimeScale; +}; + +#endif // _AP4_HINT_TRACK_READER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HmhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HmhdAtom.cpp new file mode 100644 index 000000000..4864e260a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HmhdAtom.cpp @@ -0,0 +1,108 @@ +/***************************************************************** +| +| AP4 - hmhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4HmhdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_HmhdAtom::Create ++---------------------------------------------------------------------*/ +AP4_HmhdAtom* +AP4_HmhdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_HmhdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_HmhdAtom::AP4_HmhdAtom ++---------------------------------------------------------------------*/ +AP4_HmhdAtom::AP4_HmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_HMHD, size, version, flags) +{ + stream.ReadUI16(m_MaxPduSize); + stream.ReadUI16(m_AvgPduSize); + stream.ReadUI32(m_MaxBitrate); + stream.ReadUI32(m_AvgBitrate); + stream.ReadUI32(m_Reserved); +} + +/*---------------------------------------------------------------------- +| AP4_HmhdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HmhdAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // max pdu size + result = stream.WriteUI16(m_MaxPduSize); + if (AP4_FAILED(result)) return result; + + // avg pdu size + result = stream.WriteUI16(m_AvgPduSize); + if (AP4_FAILED(result)) return result; + + // max bitrate + result = stream.WriteUI32(m_MaxBitrate); + if (AP4_FAILED(result)) return result; + + // avg bitrate + result = stream.WriteUI32(m_AvgBitrate); + if (AP4_FAILED(result)) return result; + + // reserved + result = stream.WriteUI32(m_Reserved); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HmhdAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HmhdAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("max_pdu_size", m_MaxPduSize); + inspector.AddField("avg_pdu_size", m_AvgPduSize); + inspector.AddField("max_bitrate", m_MaxBitrate); + inspector.AddField("avg_bitrate", m_AvgBitrate); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HmhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HmhdAtom.h new file mode 100644 index 000000000..c26417dc7 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4HmhdAtom.h @@ -0,0 +1,71 @@ +/***************************************************************** +| +| AP4 - hmhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_HMHD_ATOM_H_ +#define _AP4_HMHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_HmhdAtom ++---------------------------------------------------------------------*/ +class AP4_HmhdAtom : public AP4_Atom +{ +public: + // class methods + static AP4_HmhdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_HmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI16 m_MaxPduSize; + AP4_UI16 m_AvgPduSize; + AP4_UI32 m_MaxBitrate; + AP4_UI32 m_AvgBitrate; + AP4_UI32 m_Reserved; +}; + +#endif // _AP4_HMHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IkmsAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IkmsAtom.cpp new file mode 100644 index 000000000..8e2df2fb2 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IkmsAtom.cpp @@ -0,0 +1,142 @@ +/***************************************************************** +| +| AP4 - iKMS Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4IkmsAtom.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_IkmsAtom) + +/*---------------------------------------------------------------------- +| AP4_IkmsAtom::Create ++---------------------------------------------------------------------*/ +AP4_IkmsAtom* +AP4_IkmsAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version > 1) return NULL; + return new AP4_IkmsAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_IkmsAtom::AP4_IkmsAtom ++---------------------------------------------------------------------*/ +AP4_IkmsAtom::AP4_IkmsAtom(const char* kms_uri, + AP4_UI32 kms_id, + AP4_UI32 kms_version) : + AP4_Atom(AP4_ATOM_TYPE_IKMS, AP4_FULL_ATOM_HEADER_SIZE, 0, 0), + m_KmsUri(kms_uri), + m_KmsId(kms_id), + m_KmsVersion(kms_version) +{ + m_Size32 += m_KmsUri.GetLength()+1; +} + +/*---------------------------------------------------------------------- +| AP4_IkmsAtom::AP4_IkmsAtom ++---------------------------------------------------------------------*/ +AP4_IkmsAtom::AP4_IkmsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_IKMS, size, version, flags) +{ + AP4_Size string_size = size-AP4_FULL_ATOM_HEADER_SIZE; + if (m_Version == 1 && string_size >= 8) { + string_size -= 8; + stream.ReadUI32(m_KmsId); + stream.ReadUI32(m_KmsVersion); + } else { + m_KmsId = 0; + m_KmsVersion = 0; + } + if (string_size) { + char* str = new char[string_size]; + stream.Read(str, string_size); + str[string_size-1] = '\0'; // force null-termination + m_KmsUri = str; + delete[] str; + } +} + +/*---------------------------------------------------------------------- +| AP4_IkmsAtom::Clone ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_IkmsAtom::Clone() +{ + return new AP4_IkmsAtom(m_KmsUri.GetChars(), m_KmsId, m_KmsVersion); +} + +/*---------------------------------------------------------------------- +| AP4_IkmsAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IkmsAtom::WriteFields(AP4_ByteStream& stream) +{ + // handler version 1 + if (m_Version == 1) { + stream.WriteUI32(m_KmsId); + stream.WriteUI32(m_KmsVersion); + } + + // kms uri + AP4_Result result = stream.Write(m_KmsUri.GetChars(), m_KmsUri.GetLength()+1); + if (AP4_FAILED(result)) return result; + + // pad with zeros if necessary + AP4_Size padding = m_Size32-(AP4_FULL_ATOM_HEADER_SIZE+m_KmsUri.GetLength()+1); + if (m_Version == 1) padding-=8; + while (padding--) stream.WriteUI08(0); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_IkmsAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IkmsAtom::InspectFields(AP4_AtomInspector& inspector) +{ + if (m_Version == 1) { + char id[5]; + AP4_FormatFourChars(id, m_KmsId); + inspector.AddField("kms_id", id); + inspector.AddField("kms_version", m_KmsVersion); + } + inspector.AddField("kms_uri", m_KmsUri.GetChars()); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IkmsAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IkmsAtom.h new file mode 100644 index 000000000..7097b84bd --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IkmsAtom.h @@ -0,0 +1,76 @@ +/***************************************************************** +| +| AP4 - iKMS Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_IKMS_ATOM_H_ +#define _AP4_IKMS_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| AP4_IkmsAtom ++---------------------------------------------------------------------*/ +class AP4_IkmsAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_IkmsAtom, AP4_Atom) + + // class methods + static AP4_IkmsAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_IkmsAtom(const char* kms_uri, + AP4_UI32 kms_id = 0, + AP4_UI32 kms_version = 0); + virtual AP4_Atom* Clone(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + const AP4_String& GetKmsUri() { return m_KmsUri; } + AP4_UI32 GetKmsId() { return m_KmsId; } + AP4_UI32 GetKmsVersion() { return m_KmsVersion; } + +private: + // methods + AP4_IkmsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_String m_KmsUri; + AP4_UI32 m_KmsId; + AP4_UI32 m_KmsVersion; +}; + +#endif // _AP4_IKMS_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Interfaces.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Interfaces.h new file mode 100644 index 000000000..56502dab6 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Interfaces.h @@ -0,0 +1,70 @@ +/***************************************************************** +| +| AP4 - Common Interfaces +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_INTERFACES_H_ +#define _AP4_INTERFACES_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define AP4_RELEASE(o) do { if (o) (o)->Release(); (o) = NULL; } while (0) +#define AP4_ADD_REFERENCE(o) do { if (o) (o)->AddReference(); } while (0) + +#if !defined(AP4_CONFIG_NO_EXCEPTIONS) +/*---------------------------------------------------------------------- +| AP4_Exception ++---------------------------------------------------------------------*/ +class AP4_Exception +{ +public: + // methods + AP4_Exception(AP4_Result error) : m_Error(error) {} + + // members + AP4_Result m_Error; +}; +#endif + +/*---------------------------------------------------------------------- +| AP4_Referenceable ++---------------------------------------------------------------------*/ +class AP4_Referenceable +{ + public: + // methods + virtual ~AP4_Referenceable() {} + virtual void AddReference() = 0; + virtual void Release() = 0; +}; + +#endif // _AP4_INTERFACES_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IodsAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IodsAtom.cpp new file mode 100644 index 000000000..4baab3ce7 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IodsAtom.cpp @@ -0,0 +1,115 @@ +/***************************************************************** +| +| AP4 - iods Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4IodsAtom.h" +#include "Ap4DescriptorFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_IodsAtom) + +/*---------------------------------------------------------------------- +| AP4_IodsAtom::Create ++---------------------------------------------------------------------*/ +AP4_IodsAtom* +AP4_IodsAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_IodsAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_IodsAtom::AP4_IodsAtom ++---------------------------------------------------------------------*/ +AP4_IodsAtom::AP4_IodsAtom(AP4_ObjectDescriptor* descriptor) : + AP4_Atom(AP4_ATOM_TYPE_IODS, AP4_FULL_ATOM_HEADER_SIZE, 0, 0), + m_ObjectDescriptor(descriptor) +{ + if (m_ObjectDescriptor) m_Size32 += m_ObjectDescriptor->GetSize(); +} + +/*---------------------------------------------------------------------- +| AP4_IodsAtom::AP4_IodsAtom ++---------------------------------------------------------------------*/ +AP4_IodsAtom::AP4_IodsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_IODS, size, version, flags) +{ + // read the descriptor + AP4_Descriptor* descriptor = NULL; + if (AP4_DescriptorFactory::CreateDescriptorFromStream(stream, descriptor) == AP4_SUCCESS) { + m_ObjectDescriptor = AP4_DYNAMIC_CAST(AP4_ObjectDescriptor, descriptor); + if (m_ObjectDescriptor == NULL) delete descriptor; + } else { + m_ObjectDescriptor = NULL; + } +} + +/*---------------------------------------------------------------------- +| AP4_IodsAtom::~AP4_IodsAtom ++---------------------------------------------------------------------*/ +AP4_IodsAtom::~AP4_IodsAtom() +{ + delete m_ObjectDescriptor; +} + +/*---------------------------------------------------------------------- +| AP4_IodsAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IodsAtom::WriteFields(AP4_ByteStream& stream) +{ + // write the es descriptor + if (m_ObjectDescriptor) return m_ObjectDescriptor->Write(stream); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_IodsAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IodsAtom::InspectFields(AP4_AtomInspector& inspector) +{ + // inspect descriptor + if (m_ObjectDescriptor) { + m_ObjectDescriptor->Inspect(inspector); + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IodsAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IodsAtom.h new file mode 100644 index 000000000..41c6c4cf0 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IodsAtom.h @@ -0,0 +1,73 @@ +/***************************************************************** +| +| AP4 - iods Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_IODS_ATOM_H_ +#define _AP4_IODS_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4ObjectDescriptor.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_IodsAtom ++---------------------------------------------------------------------*/ +class AP4_IodsAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_IodsAtom, AP4_Atom) + + // class methods + static AP4_IodsAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_IodsAtom(AP4_ObjectDescriptor* descriptor); // ownership of 'descriptor' is transfered + ~AP4_IodsAtom(); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + const AP4_ObjectDescriptor* GetObjectDescriptor() const { return m_ObjectDescriptor; } + +private: + // methods + AP4_IodsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_ObjectDescriptor* m_ObjectDescriptor; +}; + +#endif // _AP4_IODS_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Ipmp.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Ipmp.cpp new file mode 100644 index 000000000..c3e057ae1 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Ipmp.cpp @@ -0,0 +1,225 @@ +/***************************************************************** +| +| AP4 - IPMP +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4ByteStream.h" +#include "Ap4Ipmp.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_IpmpDescriptor) +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_IpmpDescriptorPointer) + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptorPointer::AP4_IpmpDescriptorPointer ++---------------------------------------------------------------------*/ +AP4_IpmpDescriptorPointer::AP4_IpmpDescriptorPointer(AP4_UI08 descriptor_id) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER, 2, 1), + m_DescriptorId(descriptor_id) +{ +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptorPointer::AP4_IpmpDescriptorPointer ++---------------------------------------------------------------------*/ +AP4_IpmpDescriptorPointer::AP4_IpmpDescriptorPointer(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER, header_size, payload_size) +{ + stream.ReadUI08(m_DescriptorId); + if (m_DescriptorId == 0xFF && payload_size >= 5) { + stream.ReadUI16(m_DescriptorIdEx); + stream.ReadUI16(m_EsId); + } +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptorPointer::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IpmpDescriptorPointer::WriteFields(AP4_ByteStream& stream) +{ + stream.WriteUI08(m_DescriptorId); + if (m_DescriptorId == 0xFF) { + stream.WriteUI16(m_DescriptorIdEx); + stream.WriteUI16(m_EsId); + } + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptorPointer::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IpmpDescriptorPointer::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + inspector.StartElement("[IPMP_DescriptorPointer]", info); + inspector.AddField("IPMP_DescriptorID", m_DescriptorId); + if (m_DescriptorId == 0xFF) { + inspector.AddField("IPMP_DescriptorIDEx", m_DescriptorIdEx); + inspector.AddField("IPMP_ES_ID", m_EsId); + } + + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptor::AP4_IpmpDescriptor ++---------------------------------------------------------------------*/ +AP4_IpmpDescriptor::AP4_IpmpDescriptor(AP4_UI08 descriptor_id, AP4_UI16 ipmps_type) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR, 2, 3), + m_DescriptorId(descriptor_id), + m_IpmpsType(ipmps_type), + m_DescriptorIdEx(0), + m_ControlPointCode(0), + m_SequenceCode(0) +{ + AP4_SetMemory(m_ToolId, 0, sizeof(m_ToolId)); +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptor::AP4_IpmpDescriptor ++---------------------------------------------------------------------*/ +AP4_IpmpDescriptor::AP4_IpmpDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR, header_size, payload_size), + m_DescriptorIdEx(0), + m_ControlPointCode(0), + m_SequenceCode(0) +{ + stream.ReadUI08(m_DescriptorId); + stream.ReadUI16(m_IpmpsType); + AP4_SetMemory(m_ToolId, 0, sizeof(m_ToolId)); + if (m_DescriptorId == 0xFF && m_IpmpsType == 0xFFFF) { + AP4_Size fields_size = 3+3; + stream.ReadUI16(m_DescriptorIdEx); + stream.Read(m_ToolId, 16); + stream.ReadUI08(m_ControlPointCode); + if (m_ControlPointCode > 0) { + stream.ReadUI08(m_SequenceCode); + ++fields_size; + } + if (fields_size < payload_size) { + m_Data.SetDataSize(payload_size-fields_size); + stream.Read(m_Data.UseData(), payload_size-fields_size); + } + } else if (m_IpmpsType == 0) { + if (payload_size > 3) { + char* buffer = new char[1+payload_size-3]; + buffer[payload_size-3] = '\0'; + stream.Read(buffer, payload_size-3); + m_Url.Assign(buffer, payload_size-3); + delete[] buffer; + } + } else { + if (payload_size > 3) { + m_Data.SetDataSize(payload_size-3); + stream.Read(m_Data.UseData(), payload_size-3); + } + } +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptor::SetData ++---------------------------------------------------------------------*/ +void +AP4_IpmpDescriptor::SetData(const unsigned char* data, AP4_Size data_size) +{ + m_Data.SetData(data, data_size); + m_PayloadSize += data_size; + m_HeaderSize = MinHeaderSize(m_PayloadSize); +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IpmpDescriptor::WriteFields(AP4_ByteStream& stream) +{ + stream.WriteUI08(m_DescriptorId); + stream.WriteUI16(m_IpmpsType); + if (m_DescriptorId == 0xFF && m_IpmpsType == 0xFFFF) { + stream.WriteUI16(m_DescriptorIdEx); + stream.Write(m_ToolId, 16); + stream.WriteUI08(m_ControlPointCode); + if (m_ControlPointCode > 0) { + stream.WriteUI08(m_SequenceCode); + } + if (m_Data.GetDataSize()) { + stream.Write(m_Data.GetData(), m_Data.GetDataSize()); + } + } else if (m_IpmpsType == 0) { + stream.Write(m_Url.GetChars(), m_Url.GetLength()+1); + } else { + stream.Write(m_Data.GetData(), m_Data.GetDataSize()); + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IpmpDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + inspector.StartElement("[IPMP_Descriptor]", info); + inspector.AddField("IPMP_DescriptorID", m_DescriptorId); + inspector.AddField("IPMPS_Type", m_IpmpsType, AP4_AtomInspector::HINT_HEX); + if (m_DescriptorId == 0xFF && m_IpmpsType == 0xFFFF) { + inspector.AddField("IPMP_DescriptorIDEx", m_DescriptorIdEx); + inspector.AddField("IPMP_ToolID", (const unsigned char*)(&m_ToolId[0]), 16, AP4_AtomInspector::HINT_HEX); + inspector.AddField("controlPointCode", m_ControlPointCode); + if (m_ControlPointCode > 0) { + inspector.AddField("sequenceCode", m_SequenceCode); + } + } else if (m_IpmpsType == 0) { + inspector.AddField("URL", m_Url.GetChars()); + } else { + inspector.AddField("data size", m_Data.GetDataSize()); + } + + inspector.EndElement(); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Ipmp.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Ipmp.h new file mode 100644 index 000000000..52370af6d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Ipmp.h @@ -0,0 +1,112 @@ +/***************************************************************** +| +| AP4 - IPMP +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_IPMP_H_ +#define _AP4_IPMP_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4String.h" +#include "Ap4Descriptor.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER = 0x0A; +const AP4_UI08 AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR = 0x0B; + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptorPointer ++---------------------------------------------------------------------*/ +class AP4_IpmpDescriptorPointer : public AP4_Descriptor +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_IpmpDescriptorPointer, AP4_Descriptor) + + // methods + AP4_IpmpDescriptorPointer(AP4_UI08 descriptor_id); + AP4_IpmpDescriptorPointer(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + AP4_UI08 GetDescriptorId() const { return m_DescriptorId; } + AP4_UI16 GetDescriptorIdEx() const { return m_DescriptorIdEx; } + AP4_UI16 GetEsId() const { return m_EsId; } + +private: + // members + AP4_UI08 m_DescriptorId; + AP4_UI16 m_DescriptorIdEx; + AP4_UI16 m_EsId; +}; + +/*---------------------------------------------------------------------- +| AP4_IpmpDescriptor ++---------------------------------------------------------------------*/ +class AP4_IpmpDescriptor : public AP4_Descriptor +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_IpmpDescriptor, AP4_Descriptor) + + // methods + AP4_IpmpDescriptor(AP4_UI08 descriptor_id, AP4_UI16 ipmps_type); + AP4_IpmpDescriptor(AP4_ByteStream& stream, + AP4_Size header_size, + AP4_Size payload_size); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + AP4_UI08 GetDescriptorId() const { return m_DescriptorId; } + AP4_UI16 GetIpmpsType() const { return m_IpmpsType; } + AP4_UI16 GetDescriptorIdEx() const { return m_DescriptorIdEx; } + const AP4_UI08* GetToolId() const { return m_ToolId; } + AP4_UI08 GetControlPointCode() const { return m_ControlPointCode; } + AP4_UI08 GetSequenceCode() const { return m_SequenceCode; } + const AP4_String& GetUrl() const { return m_Url; } + const AP4_DataBuffer& GetData() const { return m_Data; } + void SetData(const unsigned char* data, AP4_Size data_size); + +private: + // members + AP4_UI08 m_DescriptorId; + AP4_UI16 m_IpmpsType; + AP4_UI16 m_DescriptorIdEx; + AP4_UI08 m_ToolId[16]; + AP4_UI08 m_ControlPointCode; + AP4_UI08 m_SequenceCode; + AP4_String m_Url; + AP4_DataBuffer m_Data; +}; + +#endif // _AP4_IPMP_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IproAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IproAtom.cpp new file mode 100644 index 000000000..bf85194b1 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IproAtom.cpp @@ -0,0 +1,109 @@ +/***************************************************************** +| +| AP4 - ipro Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4IproAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" +#include "Ap4SampleEntry.h" +#include "Ap4SampleTable.h" +#include "Ap4SampleDescription.h" + +/*---------------------------------------------------------------------- +| AP4_IproAtom::Create ++---------------------------------------------------------------------*/ +AP4_IproAtom* +AP4_IproAtom::Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_IproAtom(size, version, flags, stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_IproAtom::AP4_IproAtom ++---------------------------------------------------------------------*/ +AP4_IproAtom::AP4_IproAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_ContainerAtom(AP4_ATOM_TYPE_IPRO, size, false, version, flags) +{ + // read the number of entries + AP4_UI16 entry_count; + stream.ReadUI16(entry_count); + + // read all entries + AP4_LargeSize bytes_available = size-AP4_FULL_ATOM_HEADER_SIZE-2; + for (unsigned int i=0; i<entry_count; i++) { + AP4_Atom* atom; + if (AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(stream, + bytes_available, + atom))) { + atom->SetParent(this); + m_Children.Add(atom); + } + } +} + +/*---------------------------------------------------------------------- +| AP4_IproAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IproAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // entry count + result = stream.WriteUI16(m_Children.ItemCount()); + if (AP4_FAILED(result)) return result; + + // entries + return m_Children.Apply(AP4_AtomListWriter(stream)); +} + +/*---------------------------------------------------------------------- +| AP4_IproAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IproAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("entry-count", m_Children.ItemCount()); + + // inspect children + m_Children.Apply(AP4_AtomListInspector(inspector)); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IproAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IproAtom.h new file mode 100644 index 000000000..a5c7d0d7f --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IproAtom.h @@ -0,0 +1,64 @@ +/***************************************************************** +| +| AP4 - ipro Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_IPRO_ATOM_H_ +#define _AP4_IPRO_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Array.h" +#include "Ap4ContainerAtom.h" + +/*---------------------------------------------------------------------- +| AP4_IproAtom ++---------------------------------------------------------------------*/ +class AP4_IproAtom : public AP4_ContainerAtom +{ +public: + // class methods + static AP4_IproAtom* Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_IproAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); +}; + +#endif // _AP4_IPRO_ATOM_H_ + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsfmAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsfmAtom.cpp new file mode 100644 index 000000000..8cd839eae --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsfmAtom.cpp @@ -0,0 +1,127 @@ +/***************************************************************** +| +| AP4 - iSFM Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4IsfmAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_IsfmAtom) + +/*---------------------------------------------------------------------- +| AP4_IsfmAtom::Create ++---------------------------------------------------------------------*/ +AP4_IsfmAtom* +AP4_IsfmAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_IsfmAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_IsfmAtom::AP4_IsfmAtom ++---------------------------------------------------------------------*/ +AP4_IsfmAtom::AP4_IsfmAtom(bool selective_encryption, + AP4_UI08 key_length_indicator, + AP4_UI08 iv_length) : + AP4_Atom(AP4_ATOM_TYPE_ISFM, AP4_FULL_ATOM_HEADER_SIZE+3, 0, 0), + m_SelectiveEncryption(selective_encryption), + m_KeyIndicatorLength(key_length_indicator), + m_IvLength(iv_length) +{ +} + +/*---------------------------------------------------------------------- +| AP4_IsfmAtom::AP4_IsfmAtom ++---------------------------------------------------------------------*/ +AP4_IsfmAtom::AP4_IsfmAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_ISFM, size, version, flags) +{ + AP4_UI08 s; + stream.ReadUI08(s); + m_SelectiveEncryption = ((s&0x80) != 0); + stream.ReadUI08(m_KeyIndicatorLength); + stream.ReadUI08(m_IvLength); +} + +/*---------------------------------------------------------------------- +| AP4_IsfmAtom::Clone ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_IsfmAtom::Clone() +{ + return new AP4_IsfmAtom(m_SelectiveEncryption, + m_KeyIndicatorLength, + m_IvLength); +} + +/*---------------------------------------------------------------------- +| AP4_IsfmAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IsfmAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // selective encryption + result = stream.WriteUI08(m_SelectiveEncryption ? 0x80 : 0); + if (AP4_FAILED(result)) return result; + + // key indicator length + result = stream.WriteUI08(m_KeyIndicatorLength); + if (AP4_FAILED(result)) return result; + + // IV length + result = stream.WriteUI08(m_IvLength); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_IsfmAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IsfmAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("selective_encryption", m_SelectiveEncryption); + inspector.AddField("key_indicator_length", m_KeyIndicatorLength); + inspector.AddField("IV_length", m_IvLength); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsfmAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsfmAtom.h new file mode 100644 index 000000000..be6ab8382 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsfmAtom.h @@ -0,0 +1,75 @@ +/***************************************************************** +| +| AP4 - iSFM Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_ISFM_ATOM_H_ +#define _AP4_ISFM_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_IsfmAtom ++---------------------------------------------------------------------*/ +class AP4_IsfmAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_IsfmAtom, AP4_Atom) + + // class methods + static AP4_IsfmAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_IsfmAtom(bool m_SelectiveEncryption, + AP4_UI08 m_KeyIndicatorLength, + AP4_UI08 m_IvLength); + virtual AP4_Atom* Clone(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + bool GetSelectiveEncryption() { return m_SelectiveEncryption; } + AP4_UI08 GetKeyIndicatorLength() { return m_KeyIndicatorLength; } + AP4_UI08 GetIvLength() { return m_IvLength; } + +private: + // methods + AP4_IsfmAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + bool m_SelectiveEncryption; + AP4_UI08 m_KeyIndicatorLength; + AP4_UI08 m_IvLength; +}; + +#endif // _AP4_ISFM_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsltAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsltAtom.cpp new file mode 100644 index 000000000..686e68e00 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsltAtom.cpp @@ -0,0 +1,78 @@ +/***************************************************************** +| +| AP4 - iSLT Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4IsltAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_IsltAtom) + +/*---------------------------------------------------------------------- +| AP4_IsltAtom::AP4_IsltAtom ++---------------------------------------------------------------------*/ +AP4_IsltAtom::AP4_IsltAtom(const AP4_UI08* salt) : + AP4_Atom(AP4_ATOM_TYPE_ISLT, AP4_ATOM_HEADER_SIZE+8) +{ + for (unsigned int i=0; i<8; i++) { + m_Salt[i] = salt[i]; + } +} + +/*---------------------------------------------------------------------- +| AP4_IsltAtom::AP4_IsltAtom ++---------------------------------------------------------------------*/ +AP4_IsltAtom::AP4_IsltAtom(AP4_UI32 size, AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_ISLT, size) +{ + stream.Read((void*)m_Salt, 8); +} + +/*---------------------------------------------------------------------- +| AP4_IsltAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IsltAtom::WriteFields(AP4_ByteStream& stream) +{ + return stream.Write((const void*)m_Salt, 8); +} + +/*---------------------------------------------------------------------- +| AP4_IsltAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_IsltAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("salt", m_Salt, 8); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsltAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsltAtom.h new file mode 100644 index 000000000..949251acb --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsltAtom.h @@ -0,0 +1,68 @@ +/***************************************************************** +| +| AP4 - iSLT Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_ISLT_ATOM_H_ +#define _AP4_ISLT_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_IsltAtom ++---------------------------------------------------------------------*/ +class AP4_IsltAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_IsltAtom, AP4_Atom) + + // class methods + static AP4_IsltAtom* Create(AP4_Size size, AP4_ByteStream& stream) { + if (size != AP4_ATOM_HEADER_SIZE+8) return NULL; + return new AP4_IsltAtom(size, stream); + } + + // methods + AP4_IsltAtom(const AP4_UI08* salt); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + const AP4_UI08* GetSalt() { return m_Salt; } + +private: + // methods + AP4_IsltAtom(AP4_UI32 size, AP4_ByteStream& stream); + + // members + AP4_UI08 m_Salt[8]; +}; + +#endif // _AP4_ISLT_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsmaCryp.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsmaCryp.cpp new file mode 100644 index 000000000..569ca4951 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsmaCryp.cpp @@ -0,0 +1,509 @@ +/*****************************************************************
+|
+| AP4 - ISMA E&A Support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4IsmaCryp.h"
+#include "Ap4SchmAtom.h"
+#include "Ap4StsdAtom.h"
+#include "Ap4Sample.h"
+#include "Ap4StreamCipher.h"
+#include "Ap4IsfmAtom.h"
+#include "Ap4FrmaAtom.h"
+#include "Ap4IkmsAtom.h"
+#include "Ap4IsfmAtom.h"
+#include "Ap4IsltAtom.h"
+#include "Ap4Utils.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4HdlrAtom.h"
+
+/*----------------------------------------------------------------------
+| AP4_IsmaCipher::CreateSampleDecrypter
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaCipher::CreateSampleDecrypter(AP4_ProtectedSampleDescription* sample_description,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_IsmaCipher*& decrypter)
+{
+ // check parameters
+ if (key == NULL || block_cipher_factory == NULL) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+ decrypter = NULL;
+
+ // create the cipher
+ AP4_BlockCipher* block_cipher = NULL;
+ AP4_Result result = block_cipher_factory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::ENCRYPT,
+ key,
+ key_size,
+ block_cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // get the scheme info atom
+ AP4_ContainerAtom* schi = sample_description->GetSchemeInfo()->GetSchiAtom();
+ if (schi == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // get the cipher params
+ AP4_IsfmAtom* isfm = AP4_DYNAMIC_CAST(AP4_IsfmAtom, schi->FindChild("iSFM"));
+ if (isfm == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // get the salt
+ AP4_IsltAtom* salt = AP4_DYNAMIC_CAST(AP4_IsltAtom, schi->FindChild("iSLT"));
+
+ // instantiate the decrypter
+ decrypter = new AP4_IsmaCipher(block_cipher,
+ salt?salt->GetSalt():NULL,
+ isfm->GetIvLength(),
+ isfm->GetKeyIndicatorLength(),
+ isfm->GetSelectiveEncryption());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaCrypCipher::AP4_IsmaCipher
++---------------------------------------------------------------------*/
+AP4_IsmaCipher::AP4_IsmaCipher(AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt,
+ AP4_UI08 iv_length,
+ AP4_UI08 key_indicator_length,
+ bool selective_encryption) :
+ m_IvLength(iv_length),
+ m_KeyIndicatorLength(key_indicator_length),
+ m_SelectiveEncryption(selective_encryption)
+{
+ // NOTE: we do not handle key indicators yet, so there is only one key.
+
+ // left-align the salt
+ unsigned char salt_128[AP4_CIPHER_BLOCK_SIZE];
+ unsigned int i=0;
+ if (salt) {
+ for (; i<8; i++) {
+ salt_128[i] = salt[i];
+ }
+ }
+ for (; i<AP4_CIPHER_BLOCK_SIZE; i++) {
+ salt_128[i] = 0;
+ }
+
+ // create a cipher
+ m_Cipher = new AP4_CtrStreamCipher(block_cipher, salt_128, iv_length);
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaCipher::~AP4_IsmaCipher
++---------------------------------------------------------------------*/
+AP4_IsmaCipher::~AP4_IsmaCipher()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaCipher::GetDecryptedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_IsmaCipher::GetDecryptedSampleSize(AP4_Sample& sample)
+{
+ AP4_Size isma_header_size = m_KeyIndicatorLength + m_IvLength;
+ if (m_SelectiveEncryption) {
+ ++isma_header_size;
+ }
+ return sample.GetSize()-isma_header_size;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaCipher::DecryptSampleData
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaCipher::DecryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ const AP4_UI08* /*iv*/)
+{
+ bool is_encrypted = true;
+ const AP4_UI08* in = data_in.GetData();
+ AP4_Size in_size = data_in.GetDataSize();
+ AP4_Size header_size;
+
+ // default to 0 output
+ data_out.SetDataSize(0);
+
+ // check the selective encryption flag
+ if (in_size < 1) return AP4_ERROR_INVALID_FORMAT;
+ if (m_SelectiveEncryption) {
+ is_encrypted = ((in[0]&0x80)!=0);
+ in++;
+ }
+
+ // check the header size
+ header_size = (m_SelectiveEncryption?1:0)+
+ (is_encrypted?m_KeyIndicatorLength+m_IvLength:0);
+ if (header_size > in_size) return AP4_ERROR_INVALID_FORMAT;
+
+ // process the sample data
+ AP4_Size payload_size = in_size-header_size;
+ data_out.SetDataSize(payload_size);
+ AP4_UI08* out = data_out.UseData();
+ if (is_encrypted) {
+ // get the IV
+ const AP4_UI08* iv = in;
+ in += m_IvLength;
+
+ // get the key indicator (we only support up to 32 bits)
+ unsigned int to_read = m_KeyIndicatorLength;
+ while (to_read > 4) {
+ // skip anything above 4 bytes
+ to_read--;
+ in++;
+ }
+ AP4_UI32 key_indicator = 0;
+ while (to_read--) {
+ key_indicator = (key_indicator<<8) | *in++;
+ header_size++;
+ }
+ // we only support key indicator = 0 for now... (TODO)
+ if (key_indicator != 0) {
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+
+ m_Cipher->SetIV(iv);
+ m_Cipher->ProcessBuffer(in, payload_size, out);
+ } else {
+ AP4_CopyMemory(out, in, payload_size);
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaCipher::EncryptSampleData
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaCipher::EncryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ AP4_UI32 iv)
+{
+ // setup the buffers
+ const unsigned char* in = data_in.GetData();
+ data_out.SetDataSize(data_in.GetDataSize()+4);
+ unsigned char* out = data_out.UseData();
+
+ // IV on 4 bytes
+ AP4_BytesFromUInt32BE(out, iv);
+
+ // encrypt the payload
+ m_Cipher->SetIV(out);
+ AP4_Size data_size = data_in.GetDataSize();
+ m_Cipher->ProcessBuffer(in, data_size, out+4);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackDecrypter::Create
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaTrackDecrypter::Create(const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_ProtectedSampleDescription* sample_description,
+ AP4_SampleEntry* sample_entry,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_IsmaTrackDecrypter*& decrypter)
+{
+ // instantiate the cipher
+ AP4_IsmaCipher* cipher = NULL;
+ decrypter = NULL;
+ AP4_Result result = AP4_IsmaCipher::CreateSampleDecrypter(sample_description,
+ key,
+ key_size,
+ block_cipher_factory,
+ cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // instanciate the object
+ decrypter = new AP4_IsmaTrackDecrypter(cipher,
+ sample_entry,
+ sample_description->GetOriginalFormat());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackDecrypter::AP4_IsmaTrackDecrypter
++---------------------------------------------------------------------*/
+AP4_IsmaTrackDecrypter::AP4_IsmaTrackDecrypter(AP4_IsmaCipher* cipher,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 original_format) :
+ m_Cipher(cipher),
+ m_SampleEntry(sample_entry),
+ m_OriginalFormat(original_format)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackDecrypter::~AP4_IsmaTrackDecrypter
++---------------------------------------------------------------------*/
+AP4_IsmaTrackDecrypter::~AP4_IsmaTrackDecrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackDecrypter::GetProcessedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_IsmaTrackDecrypter::GetProcessedSampleSize(AP4_Sample& sample)
+{
+ return m_Cipher->GetDecryptedSampleSize(sample);
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackDecrypter::ProcessTrack
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaTrackDecrypter::ProcessTrack()
+{
+ m_SampleEntry->SetType(m_OriginalFormat);
+ m_SampleEntry->DeleteChild(AP4_ATOM_TYPE_SINF);
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaDecrypter::ProcessSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaTrackDecrypter::ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out)
+{
+ return m_Cipher->DecryptSampleData(data_in, data_out);
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackEncrypter
++---------------------------------------------------------------------*/
+class AP4_IsmaTrackEncrypter : public AP4_Processor::TrackHandler {
+public:
+ // constructor
+ AP4_IsmaTrackEncrypter(const char* kms_uri,
+ AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 format);
+ virtual ~AP4_IsmaTrackEncrypter();
+
+ // methods
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample);
+ virtual AP4_Result ProcessTrack();
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out);
+
+private:
+ // members
+ AP4_String m_KmsUri;
+ AP4_IsmaCipher* m_Cipher;
+ AP4_SampleEntry* m_SampleEntry;
+ AP4_UI32 m_Format;
+ AP4_UI32 m_Counter;
+};
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackEncrypter::AP4_IsmaTrackEncrypter
++---------------------------------------------------------------------*/
+AP4_IsmaTrackEncrypter::AP4_IsmaTrackEncrypter(
+ const char* kms_uri,
+ AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 format) :
+ m_KmsUri(kms_uri),
+ m_SampleEntry(sample_entry),
+ m_Format(format),
+ m_Counter(0)
+{
+ // instantiate the cipher (fixed params for now)
+ m_Cipher = new AP4_IsmaCipher(block_cipher, salt, 4, 0, false);
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackEncrypter::~AP4_IsmaTrackEncrypter
++---------------------------------------------------------------------*/
+AP4_IsmaTrackEncrypter::~AP4_IsmaTrackEncrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackEncrypter::GetProcessedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_IsmaTrackEncrypter::GetProcessedSampleSize(AP4_Sample& sample)
+{
+ return sample.GetSize()+4; //fixed header size for now
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackEncrypter::ProcessTrack
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaTrackEncrypter::ProcessTrack()
+{
+ // sinf container
+ AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF);
+
+ // original format
+ AP4_FrmaAtom* frma = new AP4_FrmaAtom(m_SampleEntry->GetType());
+
+ // scheme
+ AP4_SchmAtom* schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_IAEC, 1);
+
+ // scheme info
+ AP4_ContainerAtom* schi = new AP4_ContainerAtom(AP4_ATOM_TYPE_SCHI);
+ AP4_IkmsAtom* ikms = new AP4_IkmsAtom(m_KmsUri.GetChars());
+ AP4_IsfmAtom* isfm = new AP4_IsfmAtom(m_Cipher->GetSelectiveEncryption(),
+ m_Cipher->GetKeyIndicatorLength(),
+ m_Cipher->GetIvLength());
+ AP4_IsltAtom* islt = new AP4_IsltAtom(m_Cipher->GetCipher()->GetIV());
+
+ // populate the schi container
+ schi->AddChild(ikms);
+ schi->AddChild(isfm);
+ schi->AddChild(islt);
+
+ // populate the sinf container
+ sinf->AddChild(frma);
+ sinf->AddChild(schm);
+ sinf->AddChild(schi);
+
+ // add the sinf atom to the sample description
+ m_SampleEntry->AddChild(sinf);
+
+ // change the atom type of the sample description
+ m_SampleEntry->SetType(m_Format);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackEncrypter::ProcessSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IsmaTrackEncrypter::ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out)
+{
+ AP4_Result result = m_Cipher->EncryptSampleData(data_in, data_out, m_Counter);
+ if (AP4_FAILED(result)) return result;
+
+ m_Counter += (data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE-1)/AP4_CIPHER_BLOCK_SIZE;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaEncryptingProcessor::AP4_IsmaEncryptingProcessor
++---------------------------------------------------------------------*/
+AP4_IsmaEncryptingProcessor::AP4_IsmaEncryptingProcessor(const char* kms_uri,
+ AP4_BlockCipherFactory* block_cipher_factory) :
+ m_KmsUri(kms_uri)
+{
+ if (block_cipher_factory == NULL) {
+ m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
+ } else {
+ m_BlockCipherFactory = block_cipher_factory;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_IsmaEncryptingProcessor:CreateTrackHandler
++---------------------------------------------------------------------*/
+AP4_Processor::TrackHandler*
+AP4_IsmaEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
+{
+ // find the stsd atom
+ AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
+
+ // avoid tracks with no stsd atom (should not happen)
+ if (stsd == NULL) return NULL;
+
+ // only look at the first sample description
+ AP4_SampleEntry* entry = stsd->GetSampleEntry(0);
+ if (entry == NULL) return NULL;
+
+ // create a handler for this track if we have a key for it and we know
+ // how to map the type
+ const AP4_UI08* key;
+ const AP4_UI08* salt;
+ AP4_UI32 format = 0;
+ if (AP4_SUCCEEDED(m_KeyMap.GetKeyAndIv(trak->GetId(), key, salt))) {
+ switch (entry->GetType()) {
+ case AP4_ATOM_TYPE_MP4A:
+ format = AP4_ATOM_TYPE_ENCA;
+ break;
+
+ case AP4_ATOM_TYPE_MP4V:
+ case AP4_ATOM_TYPE_AVC1:
+ format = AP4_ATOM_TYPE_ENCV;
+ break;
+
+ default: {
+ // try to find if this is audio or video
+ AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, trak->FindChild("mdia/hdlr"));
+ if (hdlr) {
+ switch (hdlr->GetHandlerType()) {
+ case AP4_HANDLER_TYPE_SOUN:
+ format = AP4_ATOM_TYPE_ENCA;
+ break;
+
+ case AP4_HANDLER_TYPE_VIDE:
+ format = AP4_ATOM_TYPE_ENCV;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (format) {
+ // create the block cipher
+ AP4_BlockCipher* block_cipher = NULL;
+ AP4_Result result = m_BlockCipherFactory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::ENCRYPT,
+ key,
+ AP4_CIPHER_BLOCK_SIZE,
+ block_cipher);
+ if (AP4_FAILED(result)) return NULL;
+
+ // create the encrypter
+ return new AP4_IsmaTrackEncrypter(m_KmsUri.GetChars(),
+ block_cipher,
+ salt,
+ entry,
+ format);
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsmaCryp.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsmaCryp.h new file mode 100644 index 000000000..34cde13d8 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4IsmaCryp.h @@ -0,0 +1,150 @@ +/*****************************************************************
+|
+| AP4 - ISMA E&A support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+#ifndef _AP4_ISMACRYP_H_
+#define _AP4_ISMACRYP_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4SampleEntry.h"
+#include "Ap4Atom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4SampleDescription.h"
+#include "Ap4Processor.h"
+#include "Ap4Protection.h"
+
+/*----------------------------------------------------------------------
+| class references
++---------------------------------------------------------------------*/
+class AP4_CtrStreamCipher;
+class AP4_IsfmAtom;
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_IAEC = AP4_ATOM_TYPE('i','A','E','C');
+
+/*----------------------------------------------------------------------
+| AP4_IsmaCipher
++---------------------------------------------------------------------*/
+class AP4_IsmaCipher : public AP4_SampleDecrypter
+{
+public:
+ // factory
+ static AP4_Result CreateSampleDecrypter(AP4_ProtectedSampleDescription* sample_description,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_IsmaCipher*& decrypter);
+
+ // constructor and destructor
+ AP4_IsmaCipher(AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt,
+ AP4_UI08 iv_length,
+ AP4_UI08 key_indicator_length,
+ bool selective_encryption);
+ ~AP4_IsmaCipher();
+ AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ AP4_UI32 offset);
+ AP4_Result DecryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ const AP4_UI08* iv = NULL);
+ AP4_Size GetDecryptedSampleSize(AP4_Sample& sample);
+ AP4_CtrStreamCipher* GetCipher() { return m_Cipher; }
+ AP4_UI08 GetIvLength() { return m_IvLength; }
+ AP4_UI08 GetKeyIndicatorLength() { return m_KeyIndicatorLength; }
+ bool GetSelectiveEncryption(){ return m_SelectiveEncryption;}
+
+private:
+ // members
+ AP4_CtrStreamCipher* m_Cipher;
+ AP4_UI08 m_IvLength;
+ AP4_UI08 m_KeyIndicatorLength;
+ bool m_SelectiveEncryption;
+};
+
+/*----------------------------------------------------------------------
+| AP4_IsmaTrackDecrypter
++---------------------------------------------------------------------*/
+class AP4_IsmaTrackDecrypter : public AP4_Processor::TrackHandler {
+public:
+ // construction
+ static AP4_Result Create(const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_ProtectedSampleDescription* sample_description,
+ AP4_SampleEntry* sample_entry,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_IsmaTrackDecrypter*& decrypter);
+
+ virtual ~AP4_IsmaTrackDecrypter();
+
+ // methods
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample);
+ virtual AP4_Result ProcessTrack();
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out);
+
+private:
+ // constructor
+ AP4_IsmaTrackDecrypter(AP4_IsmaCipher* cipher,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 original_format);
+
+ // members
+ AP4_IsmaCipher* m_Cipher;
+ AP4_SampleEntry* m_SampleEntry;
+ AP4_UI32 m_OriginalFormat;
+};
+
+/*----------------------------------------------------------------------
+| AP4_IsmaEncryptingProcessor
++---------------------------------------------------------------------*/
+class AP4_IsmaEncryptingProcessor : public AP4_Processor
+{
+public:
+ // constructors and destructor
+ AP4_IsmaEncryptingProcessor(const char* kms_uri,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+
+ // accessors
+ AP4_ProtectionKeyMap& GetKeyMap() { return m_KeyMap; }
+
+ // methods
+ virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
+
+private:
+ // members
+ AP4_ProtectionKeyMap m_KeyMap;
+ AP4_String m_KmsUri;
+ AP4_BlockCipherFactory* m_BlockCipherFactory;
+};
+
+#endif // _AP4_ISMACRYP_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4LinearReader.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4LinearReader.cpp new file mode 100644 index 000000000..e8c32b558 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4LinearReader.cpp @@ -0,0 +1,274 @@ +/***************************************************************** +| +| AP4 - Linear Sample Reader +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4LinearReader.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| AP4_LinearReader::AP4_LinearReader ++---------------------------------------------------------------------*/ +AP4_LinearReader::AP4_LinearReader(AP4_Movie& movie, AP4_Size max_buffer) : + m_Movie(movie), + m_BufferFullness(0), + m_BufferFullnessPeak(0), + m_MaxBufferFullness(max_buffer) +{ +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::~AP4_LinearReader ++---------------------------------------------------------------------*/ +AP4_LinearReader::~AP4_LinearReader() +{ + for (unsigned int i=0; i<m_Trackers.ItemCount(); i++) { + delete m_Trackers[i]; + } +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::EnableTrack ++---------------------------------------------------------------------*/ +AP4_Result +AP4_LinearReader::EnableTrack(AP4_UI32 track_id) +{ + // check if we don't already have this + if (FindTracker(track_id)) return AP4_SUCCESS; + + // find the track in the movie + AP4_Track* track = m_Movie.GetTrack(track_id); + if (track == NULL) return AP4_ERROR_NO_SUCH_ITEM; + + // create a new entry for the track + return m_Trackers.Append(new Tracker(track)); +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::SetSampleIndex ++---------------------------------------------------------------------*/ +AP4_Result +AP4_LinearReader::SetSampleIndex(AP4_UI32 track_id, AP4_UI32 sample_index) +{ + Tracker* tracker = FindTracker(track_id); + if (tracker == NULL) return AP4_ERROR_INVALID_PARAMETERS; + assert(tracker->m_Track); + delete tracker->m_NextSample; + tracker->m_NextSample = NULL; + if (sample_index >= tracker->m_Track->GetSampleCount()) { + return AP4_ERROR_OUT_OF_RANGE; + } + tracker->m_Eos = false; + tracker->m_NextSampleIndex = sample_index; + + // empty any queued samples + for (AP4_List<SampleBuffer>::Item* item = tracker->m_Samples.FirstItem(); + item; + item = item->GetNext()) { + SampleBuffer* buffer = item->GetData(); + m_BufferFullness -= buffer->m_Sample->GetSize(); + delete buffer; + } + tracker->m_Samples.Clear(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::Advance ++---------------------------------------------------------------------*/ +AP4_Result +AP4_LinearReader::Advance() +{ + // first, check if we have space to advance + if (m_BufferFullness >= m_MaxBufferFullness) { + return AP4_ERROR_NOT_ENOUGH_SPACE; + } + + AP4_UI64 min_offset = (AP4_UI64)(-1); + Tracker* next_tracker = NULL; + for (unsigned int i=0; i<m_Trackers.ItemCount(); i++) { + Tracker* tracker = m_Trackers[i]; + if (tracker->m_Eos) continue; + + // get the next sample unless we have it already + if (tracker->m_NextSample == NULL) { + if (tracker->m_NextSampleIndex >= tracker->m_Track->GetSampleCount()) { + tracker->m_Eos = true; + continue; + } + tracker->m_NextSample = new AP4_Sample(); + AP4_Result result = tracker->m_Track->GetSample(tracker->m_NextSampleIndex, *tracker->m_NextSample); + if (AP4_FAILED(result)) { + tracker->m_Eos = true; + delete tracker->m_NextSample; + tracker->m_NextSample = NULL; + continue; + } + } + assert(tracker->m_NextSample); + + AP4_UI64 offset = tracker->m_NextSample->GetOffset(); + if (offset < min_offset) { + min_offset = offset; + next_tracker = tracker; + } + } + + if (next_tracker) { + // read the sample into a buffer + assert(next_tracker->m_NextSample); + SampleBuffer* buffer = new SampleBuffer(next_tracker->m_NextSample); + AP4_Result result = buffer->m_Sample->ReadData(buffer->m_Data); + if (AP4_FAILED(result)) return result; + + // add the buffer to the queue + next_tracker->m_Samples.Add(buffer); + m_BufferFullness += next_tracker->m_NextSample->GetSize(); + if (m_BufferFullness > m_BufferFullnessPeak) { + m_BufferFullnessPeak = m_BufferFullness; + } + next_tracker->m_NextSample = NULL; + next_tracker->m_NextSampleIndex++; + return AP4_SUCCESS; + } + + return AP4_ERROR_EOS; +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::PopSample ++---------------------------------------------------------------------*/ +bool +AP4_LinearReader::PopSample(Tracker* tracker, + AP4_Sample& sample, + AP4_DataBuffer& sample_data) +{ + SampleBuffer* head = NULL; + if (AP4_SUCCEEDED(tracker->m_Samples.PopHead(head))) { + assert(head->m_Sample); + sample = *head->m_Sample; + sample_data.SetData(head->m_Data.GetData(), head->m_Data.GetDataSize()); + assert(m_BufferFullness >= sample.GetSize()); + m_BufferFullness -= sample.GetSize(); + delete head; + return true; + } + + return false; +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::ReadNextSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_LinearReader::ReadNextSample(AP4_UI32 track_id, + AP4_Sample& sample, + AP4_DataBuffer& sample_data) +{ + if (m_Trackers.ItemCount() == 0) { + return AP4_ERROR_NO_SUCH_ITEM; + } + + // look for a sample from a specific track + Tracker* tracker = FindTracker(track_id); + if (tracker == NULL) return AP4_ERROR_INVALID_PARAMETERS; + for(;;) { + if (tracker->m_Eos) return AP4_ERROR_EOS; + + // pop a sample if we can + if (PopSample(tracker, sample, sample_data)) return AP4_SUCCESS; + + AP4_Result result = Advance(); + if (AP4_FAILED(result)) return result; + } + + return AP4_ERROR_EOS; +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::ReadNextSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_LinearReader::ReadNextSample(AP4_Sample& sample, + AP4_DataBuffer& sample_data, + AP4_UI32& track_id) +{ + if (m_Trackers.ItemCount() == 0) { + track_id = 0; + return AP4_ERROR_NO_SUCH_ITEM; + } + + // return the oldest buffered sample, if any + AP4_UI64 min_offset = (AP4_UI64)(-1); + Tracker* next_tracker = NULL; + for (;;) { + for (unsigned int i=0; i<m_Trackers.ItemCount(); i++) { + Tracker* tracker = m_Trackers[i]; + if (tracker->m_Eos) continue; + + AP4_List<SampleBuffer>::Item* item = tracker->m_Samples.FirstItem(); + if (item) { + AP4_UI64 offset = item->GetData()->m_Sample->GetOffset(); + if (offset < min_offset) { + min_offset = offset; + next_tracker = tracker; + } + } + } + + // return the sample if we have found a tracker + if (next_tracker) { + PopSample(next_tracker, sample, sample_data); + track_id = next_tracker->m_Track->GetId(); + return AP4_SUCCESS; + } + + // nothing found, read one more sample + AP4_Result result = Advance(); + if (AP4_FAILED(result)) return result; + } + + return AP4_ERROR_EOS; +} + +/*---------------------------------------------------------------------- +| AP4_LinearReader::FindTracker ++---------------------------------------------------------------------*/ +AP4_LinearReader::Tracker* +AP4_LinearReader::FindTracker(AP4_UI32 track_id) +{ + for (unsigned int i=0; i<m_Trackers.ItemCount(); i++) { + if (m_Trackers[i]->m_Track->GetId() == track_id) return m_Trackers[i]; + } + + // not found + return NULL; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4LinearReader.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4LinearReader.h new file mode 100644 index 000000000..7ebeff4f7 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4LinearReader.h @@ -0,0 +1,122 @@ +/***************************************************************** +| +| AP4 - File Writer +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_LINEAR_READER_H_ +#define _AP4_LINEAR_READER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Array.h" +#include "Ap4Movie.h" +#include "Ap4Sample.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_Track; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int AP4_LINEAR_READER_INITIALIZED = 1; +const unsigned int AP4_LINEAR_READER_FLAG_EOS = 2; + +const unsigned int AP4_LINEAR_READER_DEFAULT_BUFFER_SIZE = 4096*1024; + +/*---------------------------------------------------------------------- +| AP4_LinearReader ++---------------------------------------------------------------------*/ +class AP4_LinearReader { +public: + AP4_LinearReader(AP4_Movie& movie, AP4_Size max_buffer=AP4_LINEAR_READER_DEFAULT_BUFFER_SIZE); + ~AP4_LinearReader(); + + AP4_Result EnableTrack(AP4_UI32 track_id); + /** + * Read the next sample in storage order, from any track. + * track_id is updated to reflect the track from which the sample was read. + */ + AP4_Result ReadNextSample(AP4_Sample& sample, + AP4_DataBuffer& sample_data, + AP4_UI32& track_id); + /** + * Read the next sample in storage order from a specific track. + */ + AP4_Result ReadNextSample(AP4_UI32 track_id, + AP4_Sample& sample, + AP4_DataBuffer& sample_data); + + AP4_Result SetSampleIndex(AP4_UI32 track_id, AP4_UI32 sample_index); + + // accessors + AP4_Size GetBufferFullness() { return m_BufferFullness; } + +private: + class SampleBuffer { + public: + SampleBuffer(AP4_Sample* sample) : m_Sample(sample) {} + ~SampleBuffer() { delete m_Sample; } + AP4_Sample* m_Sample; + AP4_DataBuffer m_Data; + }; + class Tracker { + public: + Tracker(AP4_Track* track) : + m_Eos(false), + m_Track(track), + m_NextSample(NULL), + m_NextSampleIndex(0) {} + Tracker(const Tracker& other) : + m_Eos(other.m_Eos), + m_Track(other.m_Track), + m_NextSample(NULL), + m_NextSampleIndex(other.m_NextSampleIndex) {} // don't copy samples + ~Tracker() { m_Samples.DeleteReferences(); } + bool m_Eos; + AP4_Track* m_Track; + AP4_Sample* m_NextSample; + AP4_Ordinal m_NextSampleIndex; + AP4_List<SampleBuffer> m_Samples; + }; + + // methods + Tracker* FindTracker(AP4_UI32 track_id); + AP4_Result Advance(); + bool PopSample(Tracker* tracker, AP4_Sample& sample, AP4_DataBuffer& sample_data); + + // members + AP4_Movie& m_Movie; + AP4_Array<Tracker*> m_Trackers; + AP4_Size m_BufferFullness; + AP4_Size m_BufferFullnessPeak; + AP4_Size m_MaxBufferFullness; +}; + +#endif // _AP4_LINEAR_READER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4List.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4List.h new file mode 100644 index 000000000..d6a28cc63 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4List.h @@ -0,0 +1,490 @@ +/*****************************************************************
+|
+| AP4 - Lists
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_LIST_H_
+#define _AP4_LIST_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4Results.h"
+
+/*----------------------------------------------------------------------
+| forward references
++---------------------------------------------------------------------*/
+template <typename T> class AP4_List;
+
+/*----------------------------------------------------------------------
+| AP4_List
++---------------------------------------------------------------------*/
+template <typename T>
+class AP4_List
+{
+public:
+ // types
+ class Item
+ {
+ public:
+ // types
+ class Operator
+ {
+ public:
+ // methods
+ virtual ~Operator() {}
+ virtual AP4_Result Action(T* data) const = 0;
+ };
+
+ class Finder
+ {
+ public:
+ // methods
+ virtual ~Finder() {}
+ virtual AP4_Result Test(T* data) const = 0;
+ };
+
+ // methods
+ Item(T* data) : m_Data(data), m_Next(0), m_Prev(0) {}
+ ~Item() {}
+ Item* GetNext() { return m_Next; }
+ Item* GetPrev() { return m_Prev; }
+ T* GetData() { return m_Data; }
+
+ private:
+ // members
+ T* m_Data;
+ Item* m_Next;
+ Item* m_Prev;
+
+ // friends
+ friend class AP4_List;
+ };
+
+ // methods
+ AP4_List<T>(): m_ItemCount(0), m_Head(0), m_Tail(0) {}
+ virtual ~AP4_List<T>();
+ AP4_Result Clear();
+ AP4_Result Add(T* data);
+ AP4_Result Add(Item* item);
+ AP4_Result Remove(T* data);
+ AP4_Result Insert(Item* where, T* data);
+ AP4_Result Get(AP4_Ordinal idx, T*& data) const;
+ AP4_Result PopHead(T*& data);
+ AP4_Result Apply(const typename Item::Operator& op) const;
+ AP4_Result ApplyUntilFailure(const typename Item::Operator& op) const;
+ AP4_Result ApplyUntilSuccess(const typename Item::Operator& op) const ;
+ AP4_Result ReverseApply(const typename Item::Operator& op) const;
+ AP4_Result Find(const typename Item::Finder& finder, T*& data) const;
+ AP4_Result ReverseFind(const typename Item::Finder& finder, T*& data) const;
+ AP4_Result DeleteReferences();
+ AP4_Cardinal ItemCount() const { return m_ItemCount; }
+ Item* FirstItem() const { return m_Head; }
+ Item* LastItem() const { return m_Tail; }
+
+protected:
+ // members
+ AP4_Cardinal m_ItemCount;
+ Item* m_Head;
+ Item* m_Tail;
+
+private:
+ // these cannot be used
+ AP4_List<T>(const AP4_List<T>&);
+ AP4_List<T>& operator=(const AP4_List<T>&);
+};
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::~AP4_List<T>
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_List<T>::~AP4_List()
+{
+ Clear();
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Clear
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::Clear()
+{
+ Item* item = m_Head;
+
+ while (item) {
+ Item* next = item->m_Next;
+ delete item;
+ item = next;
+ }
+ m_ItemCount = 0;
+ m_Head = m_Tail = NULL;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Add
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::Add(T* data)
+{
+ return Add(new Item(data));
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Add
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_List<T>::Add(Item* item)
+{
+ // add element at the tail
+ if (m_Tail) {
+ item->m_Prev = m_Tail;
+ item->m_Next = NULL;
+ m_Tail->m_Next = item;
+ m_Tail = item;
+ } else {
+ m_Head = item;
+ m_Tail = item;
+ item->m_Next = NULL;
+ item->m_Prev = NULL;
+ }
+
+ // one more item in the list now
+ m_ItemCount++;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Remove
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_List<T>::Remove(T* data)
+{
+ Item* item = m_Head;
+
+ while (item) {
+ if (item->m_Data == data) {
+ // delete item
+ if (item->m_Prev) {
+ // item is not the head
+ if (item->m_Next) {
+ // item is not the tail
+ item->m_Next->m_Prev = item->m_Prev;
+ item->m_Prev->m_Next = item->m_Next;
+ } else {
+ // item is the tail
+ m_Tail = item->m_Prev;
+ m_Tail->m_Next = NULL;
+ }
+ } else {
+ // item is the head
+ m_Head = item->m_Next;
+ if (m_Head) {
+ // item is not the tail
+ m_Head->m_Prev = NULL;
+ } else {
+ // item is also the tail
+ m_Tail = NULL;
+ }
+ }
+
+ // delete the item
+ delete item;
+
+ // one less item in the list now
+ m_ItemCount--;
+
+ return AP4_SUCCESS;
+ }
+ item = item->m_Next;
+ }
+
+ return AP4_ERROR_NO_SUCH_ITEM;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Insert
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_List<T>::Insert(Item* where, T* data)
+{
+ Item* item = new Item(data);
+
+ if (where == NULL) {
+ // insert as the head
+ if (m_Head) {
+ // replace the current head
+ item->m_Prev = NULL;
+ item->m_Next = m_Head;
+ m_Head->m_Prev = item;
+ m_Head = item;
+ } else {
+ // this item becomes the head and tail
+ m_Head = item;
+ m_Tail = item;
+ item->m_Next = NULL;
+ item->m_Prev = NULL;
+ }
+ } else {
+ // insert after the 'where' item
+ if (where == m_Tail) {
+ // add the item at the end
+ return Add(item);
+ } else {
+ // update the links
+ item->m_Prev = where;
+ item->m_Next = where->m_Next;
+ where->m_Next->m_Prev = item;
+ where->m_Next = item;
+ }
+ }
+
+ // one more item in the list now
+ ++m_ItemCount;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Get
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_List<T>::Get(AP4_Ordinal idx, T*& data) const
+{
+ Item* item = m_Head;
+
+ if (idx < m_ItemCount) {
+ while (idx--) item = item->m_Next;
+ data = item->m_Data;
+ return AP4_SUCCESS;
+ } else {
+ data = NULL;
+ return AP4_ERROR_NO_SUCH_ITEM;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::PopHead
++---------------------------------------------------------------------*/
+template <typename T>
+AP4_Result
+AP4_List<T>::PopHead(T*& data)
+{
+ // check that we have at least one item
+ if (m_Head == NULL) {
+ return AP4_ERROR_LIST_EMPTY;
+ }
+
+ // remove the item and return it
+ data = m_Head->m_Data;
+ Item* head = m_Head;
+ m_Head = m_Head->m_Next;
+ if (m_Head) {
+ m_Head->m_Prev = NULL;
+ } else {
+ m_Tail = NULL;
+ }
+
+ // delete item
+ delete head;
+
+ // one less item in the list now
+ m_ItemCount--;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Apply
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::Apply(const typename Item::Operator& op) const
+{
+ Item* item = m_Head;
+
+ while (item) {
+ op.Action(item->m_Data);
+ item = item->m_Next;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::ApplyUntilFailure
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::ApplyUntilFailure(const typename Item::Operator& op) const
+{
+ Item* item = m_Head;
+
+ while (item) {
+ AP4_Result result;
+ result = op.Action(item->m_Data);
+ if (result != AP4_SUCCESS) return result;
+ item = item->m_Next;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::ApplyUntilSuccess
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::ApplyUntilSuccess(const typename Item::Operator& op) const
+{
+ Item* item = m_Head;
+
+ while (item) {
+ AP4_Result result;
+ result = op.Action(item->m_Data);
+ if (result == AP4_SUCCESS) return AP4_SUCCESS;
+ item = item->m_Next;
+ }
+
+ return AP4_FAILURE;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::ReverseApply
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::ReverseApply(const typename Item::Operator& op) const
+{
+ Item* item = m_Tail;
+
+ while (item) {
+ if (op.Action(item->m_Data) != AP4_SUCCESS) {
+ return AP4_ERROR_LIST_OPERATION_ABORTED;
+ }
+ item = item->m_Prev;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::Find
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::Find(const typename Item::Finder& finder, T*& data) const
+{
+ Item* item = m_Head;
+
+ while (item) {
+ if (finder.Test(item->m_Data) == AP4_SUCCESS) {
+ data = item->m_Data;
+ return AP4_SUCCESS;
+ }
+ item = item->m_Next;
+ }
+
+ data = NULL;
+ return AP4_ERROR_NO_SUCH_ITEM;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::ReverseFind
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::ReverseFind(const typename Item::Finder& finder, T*& data) const
+{
+ Item* item = m_Tail;
+
+ while (item) {
+ if (finder.Test(item->m_Data) == AP4_SUCCESS) {
+ data = item->m_Data;
+ return AP4_SUCCESS;
+ }
+ item = item->m_Prev;
+ }
+
+ data = NULL;
+ return AP4_ERROR_NO_SUCH_ITEM;
+}
+
+/*----------------------------------------------------------------------
+| AP4_List<T>::DeleteReferences
++---------------------------------------------------------------------*/
+template <typename T>
+inline
+AP4_Result
+AP4_List<T>::DeleteReferences()
+{
+ Item* item = m_Head;
+
+ while (item) {
+ Item* next = item->m_Next;
+ delete item->m_Data;
+ delete item;
+ item = next;
+ }
+
+ // no more items
+ m_Head = m_Tail = NULL;
+ m_ItemCount = 0;
+
+ return AP4_SUCCESS;
+}
+
+#endif // _AP4_LIST_H_
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Marlin.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Marlin.cpp new file mode 100644 index 000000000..c4464f5df --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Marlin.cpp @@ -0,0 +1,990 @@ +/*****************************************************************
+|
+| AP4 - Marlin File Format Support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4SchmAtom.h"
+#include "Ap4StsdAtom.h"
+#include "Ap4Sample.h"
+#include "Ap4StreamCipher.h"
+#include "Ap4FrmaAtom.h"
+#include "Ap4Utils.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4FtypAtom.h"
+#include "Ap4IodsAtom.h"
+#include "Ap4MoovAtom.h"
+#include "Ap4Track.h"
+#include "Ap4DescriptorFactory.h"
+#include "Ap4CommandFactory.h"
+#include "Ap4Marlin.h"
+#include "Ap4FileByteStream.h"
+#include "Ap4Ipmp.h"
+#include "Ap4AesBlockCipher.h"
+#include "Ap4SyntheticSampleTable.h"
+#include "Ap4HdlrAtom.h"
+#include "Ap4Hmac.h"
+#include "Ap4KeyWrap.h"
+#include "Ap4ByteStream.h"
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpAtomTypeHandler
++---------------------------------------------------------------------*/
+class AP4_MarlinIpmpAtomTypeHandler : public AP4_AtomFactory::TypeHandler
+{
+public:
+ // constructor
+ AP4_MarlinIpmpAtomTypeHandler(AP4_AtomFactory* atom_factory) :
+ m_AtomFactory(atom_factory) {}
+ virtual AP4_Result CreateAtom(AP4_Atom::Type type,
+ AP4_UI32 size,
+ AP4_ByteStream& stream,
+ AP4_Atom::Type context,
+ AP4_Atom*& atom);
+
+private:
+ // members
+ AP4_AtomFactory* m_AtomFactory;
+};
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpAtomFactory
++---------------------------------------------------------------------*/
+class AP4_MarlinIpmpAtomFactory : public AP4_DefaultAtomFactory
+{
+public:
+ // class members
+ static AP4_MarlinIpmpAtomFactory Instance;
+
+ // constructor
+ AP4_MarlinIpmpAtomFactory() {
+ AddTypeHandler(new AP4_MarlinIpmpAtomTypeHandler(this));
+ }
+};
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpAtomFactory::Instance
++---------------------------------------------------------------------*/
+AP4_MarlinIpmpAtomFactory AP4_MarlinIpmpAtomFactory::Instance;
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpAtomTypeHandler::CreateAtom
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpAtomTypeHandler::CreateAtom(AP4_Atom::Type type,
+ AP4_UI32 size,
+ AP4_ByteStream& stream,
+ AP4_Atom::Type /*context*/,
+ AP4_Atom*& atom)
+{
+ switch (type) {
+ case AP4_ATOM_TYPE_SATR:
+ atom = AP4_ContainerAtom::Create(type, size, false, false, stream, *m_AtomFactory);
+ break;
+
+ case AP4_ATOM_TYPE_STYP:
+ atom = new AP4_NullTerminatedStringAtom(type, size, stream);
+ break;
+
+ default:
+ atom = NULL;
+ }
+
+ return atom ? AP4_SUCCESS : AP4_FAILURE;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpParser:Parse
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpParser::Parse(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ AP4_List<SinfEntry>& sinf_entries,
+ bool remove_od_data)
+{
+ // check the file type
+ AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
+ if (ftyp == NULL ||
+ (ftyp->GetMajorBrand() != AP4_MARLIN_BRAND_MGSV && !ftyp->HasCompatibleBrand(AP4_MARLIN_BRAND_MGSV))) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // check the initial object descriptor and get the OD Track ID
+ AP4_IodsAtom* iods = AP4_DYNAMIC_CAST(AP4_IodsAtom, top_level.FindChild("moov/iods"));
+ AP4_UI32 od_track_id = 0;
+ if (iods == NULL) return AP4_ERROR_INVALID_FORMAT;
+ const AP4_ObjectDescriptor* od = iods->GetObjectDescriptor();
+ if (od == NULL) return AP4_ERROR_INVALID_FORMAT;
+ AP4_EsIdIncDescriptor* es_id_inc = AP4_DYNAMIC_CAST(AP4_EsIdIncDescriptor, od->FindSubDescriptor(AP4_DESCRIPTOR_TAG_ES_ID_INC));
+ if (es_id_inc == NULL) return AP4_ERROR_INVALID_FORMAT;
+ od_track_id = es_id_inc->GetTrackId();
+
+ // find the track pointed to by the descriptor
+ AP4_MoovAtom* moov = AP4_DYNAMIC_CAST(AP4_MoovAtom, top_level.GetChild(AP4_ATOM_TYPE_MOOV));
+ if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
+ AP4_TrakAtom* od_trak = NULL;
+ for (AP4_List<AP4_TrakAtom>::Item* trak_item = moov->GetTrakAtoms().FirstItem();
+ trak_item;
+ trak_item = trak_item->GetNext()) {
+ AP4_TrakAtom* trak = trak_item->GetData();
+ if (trak) {
+ if (trak->GetId() == od_track_id) {
+ od_trak = trak;
+ } else {
+ sinf_entries.Add(new SinfEntry(trak->GetId(), NULL));
+ }
+ }
+ }
+
+ // check that we have found the OD track
+ if (od_trak == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // look for the 'mpod' trak references
+ AP4_TrefTypeAtom* track_references;
+ track_references = AP4_DYNAMIC_CAST(AP4_TrefTypeAtom, od_trak->FindChild("tref/mpod"));
+ if (track_references == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // create an AP4_Track object from the trak atom and check that it has samples
+ AP4_Track* od_track = new AP4_Track(*od_trak, stream, 0);
+ if (od_track->GetSampleCount() < 1) {
+ delete od_track;
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // get the first sample (in this version, we only look at a single OD command)
+ AP4_Sample od_sample;
+ AP4_Result result = od_track->GetSample(0, od_sample);
+ if (AP4_FAILED(result)) {
+ delete od_track;
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // adapt the sample data into a byte stream for parsing
+ AP4_DataBuffer sample_data;
+ od_sample.ReadData(sample_data);
+ AP4_MemoryByteStream* sample_stream = new AP4_MemoryByteStream(sample_data);
+
+ // look for one ObjectDescriptorUpdate command and
+ // one IPMP_DescriptorUpdate command
+ AP4_DescriptorUpdateCommand* od_update = NULL;
+ AP4_DescriptorUpdateCommand* ipmp_update = NULL;
+ do {
+ AP4_Command* command = NULL;
+ result = AP4_CommandFactory::CreateCommandFromStream(*sample_stream, command);
+ if (AP4_SUCCEEDED(result)) {
+ // found a command in the sample, check the type
+ switch (command->GetTag()) {
+ case AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_UPDATE:
+ if (od_update == NULL) {
+ od_update = AP4_DYNAMIC_CAST(AP4_DescriptorUpdateCommand, command);
+ }
+ break;
+
+ case AP4_COMMAND_TAG_IPMP_DESCRIPTOR_UPDATE:
+ if (ipmp_update == NULL) {
+ ipmp_update = AP4_DYNAMIC_CAST(AP4_DescriptorUpdateCommand, command);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ } while (AP4_SUCCEEDED(result));
+ sample_stream->Release();
+ sample_stream = NULL;
+
+ // check that we have what we need
+ if (od_update == NULL || ipmp_update == NULL) {
+ delete od_track;
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // process all the object descriptors in the od update
+ for (AP4_List<AP4_Descriptor>::Item* od_item = od_update->GetDescriptors().FirstItem();
+ od_item;
+ od_item = od_item->GetNext()) {
+ od = AP4_DYNAMIC_CAST(AP4_ObjectDescriptor, od_item->GetData());
+ if (od == NULL) continue;
+
+ // find which track this od references
+ AP4_EsIdRefDescriptor* es_id_ref;
+ es_id_ref = AP4_DYNAMIC_CAST(AP4_EsIdRefDescriptor, od->FindSubDescriptor(AP4_DESCRIPTOR_TAG_ES_ID_REF));
+ if (es_id_ref == NULL ||
+ es_id_ref->GetRefIndex() > track_references->GetTrackIds().ItemCount() ||
+ es_id_ref->GetRefIndex() == 0) {
+ continue;
+ }
+ AP4_UI32 track_id = track_references->GetTrackIds()[es_id_ref->GetRefIndex()-1];
+ SinfEntry* sinf_entry = NULL;
+ for (AP4_List<SinfEntry>::Item* sinf_entry_item = sinf_entries.FirstItem();
+ sinf_entry_item;
+ sinf_entry_item = sinf_entry_item->GetNext()) {
+ sinf_entry = sinf_entry_item->GetData();
+ if (sinf_entry->m_TrackId == track_id) {
+ break; // match
+ } else {
+ sinf_entry = NULL; // no match
+ }
+ }
+ if (sinf_entry == NULL) continue; // no matching entry
+ if (sinf_entry->m_Sinf != NULL) continue; // entry already populated
+
+ // see what ipmp descriptor this od points to
+ AP4_IpmpDescriptorPointer* ipmpd_pointer;
+ ipmpd_pointer = AP4_DYNAMIC_CAST(AP4_IpmpDescriptorPointer, od->FindSubDescriptor(AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER));
+ if (ipmpd_pointer == NULL) continue; // no pointer
+
+ // find the ipmp descriptor referenced by the pointer
+ AP4_IpmpDescriptor* ipmpd = NULL;
+ for (AP4_List<AP4_Descriptor>::Item* ipmpd_item = ipmp_update->GetDescriptors().FirstItem();
+ ipmpd_item;
+ ipmpd_item = ipmpd_item->GetNext()) {
+ // check that this descriptor is of the right type
+ ipmpd = AP4_DYNAMIC_CAST(AP4_IpmpDescriptor, ipmpd_item->GetData());
+ if (ipmpd == NULL || ipmpd->GetIpmpsType() != AP4_MARLIN_IPMPS_TYPE_MGSV) continue;
+
+ // check the descriptor id
+ if (ipmpd->GetDescriptorId() == ipmpd_pointer->GetDescriptorId()) {
+ break; // match
+ } else {
+ ipmpd = NULL; // no match
+ }
+ }
+ if (ipmpd == NULL) continue; // no matching entry
+
+ // parse the ipmp data into one or more 'sinf' atoms, and keep the one with the
+ // right type
+ AP4_MemoryByteStream* data = new AP4_MemoryByteStream(ipmpd->GetData().GetData(),
+ ipmpd->GetData().GetDataSize());
+ AP4_LargeSize bytes_available = ipmpd->GetData().GetDataSize();
+ do {
+ AP4_Atom* atom = NULL;
+
+ // setup the factory with a context so we can instantiate a 'schm'
+ // atom with a slightly different format than the standard 'schm'
+ AP4_AtomFactory* factory = &AP4_MarlinIpmpAtomFactory::Instance;
+ factory->PushContext(AP4_ATOM_TYPE('m','r','l','n'));
+
+ // parse the next atom in the stream
+ result = factory->CreateAtomFromStream(*data, bytes_available, atom);
+ factory->PopContext();
+ if (AP4_FAILED(result) || atom == NULL) break;
+
+ // check that what we have parsed is indeed an 'sinf' of the right type
+ if (atom->GetType() == AP4_ATOM_TYPE_SINF) {
+ AP4_ContainerAtom* sinf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
+ AP4_SchmAtom* schm = AP4_DYNAMIC_CAST(AP4_SchmAtom, sinf->FindChild("schm"));
+ if ((schm->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACBC &&
+ schm->GetSchemeVersion() == 0x0100) ||
+ (schm->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACGK &&
+ schm->GetSchemeVersion() == 0x0100)) {
+ // store the sinf in the entry for that track
+ sinf_entry->m_Sinf = sinf;
+ break;
+ }
+ }
+ delete atom;
+ } while (AP4_SUCCEEDED(result));
+ data->Release();
+ }
+
+ // get rid of entries that have no SINF
+ for (AP4_List<SinfEntry>::Item* sinf_entry_item = sinf_entries.FirstItem();
+ sinf_entry_item;
+ sinf_entry_item = sinf_entry_item->GetNext()) {
+ SinfEntry* sinf_entry = sinf_entry_item->GetData();
+ if (sinf_entry->m_Sinf == NULL) {
+ sinf_entries.Remove(sinf_entry);
+ sinf_entry_item = sinf_entries.FirstItem();
+ continue;
+ }
+ }
+
+ // remove the iods atom and the OD track if required
+ if (remove_od_data) {
+ od_trak->Detach();
+ delete od_trak;
+ iods->Detach();
+ delete iods;
+ }
+
+ // cleanup
+ delete od_track;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpDecryptingProcessor:AP4_MarlinIpmpDecryptingProcessor
++---------------------------------------------------------------------*/
+AP4_MarlinIpmpDecryptingProcessor::AP4_MarlinIpmpDecryptingProcessor(
+ const AP4_ProtectionKeyMap* key_map, /* = NULL */
+ AP4_BlockCipherFactory* block_cipher_factory /* = NULL */){
+ if (key_map) {
+ // copy the keys
+ m_KeyMap.SetKeys(*key_map);
+ }
+
+ if (block_cipher_factory == NULL) {
+ m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
+ } else {
+ m_BlockCipherFactory = block_cipher_factory;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpDecryptingProcessor::~AP4_MarlinIpmpDecryptingProcessor
++---------------------------------------------------------------------*/
+AP4_MarlinIpmpDecryptingProcessor::~AP4_MarlinIpmpDecryptingProcessor()
+{
+ m_SinfEntries.DeleteReferences();
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpDecryptingProcessor:Initialize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpDecryptingProcessor::Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ ProgressListener* /*listener*/)
+{
+ return AP4_MarlinIpmpParser::Parse(top_level, stream, m_SinfEntries, true);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpDecryptingProcessor:CreateTrackHandler
++---------------------------------------------------------------------*/
+AP4_Processor::TrackHandler*
+AP4_MarlinIpmpDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
+{
+ // look for this track in the list of entries
+ AP4_MarlinIpmpParser::SinfEntry* sinf_entry = NULL;
+ for (AP4_List<AP4_MarlinIpmpParser::SinfEntry>::Item* sinf_entry_item = m_SinfEntries.FirstItem();
+ sinf_entry_item;
+ sinf_entry_item = sinf_entry_item->GetNext()) {
+ sinf_entry = sinf_entry_item->GetData();
+ if (sinf_entry->m_TrackId == trak->GetId()) {
+ break; // match
+ } else {
+ sinf_entry = NULL; // no match
+ }
+ }
+ if (sinf_entry == NULL) return NULL; // no matching entry
+ AP4_ContainerAtom* sinf = sinf_entry->m_Sinf;
+
+ // check the scheme
+ bool use_group_key;
+ AP4_SchmAtom* schm = AP4_DYNAMIC_CAST(AP4_SchmAtom, sinf->GetChild(AP4_ATOM_TYPE_SCHM));
+ if (schm == NULL) return NULL; // no schm
+ if (schm->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACBC &&
+ schm->GetSchemeVersion() == 0x0100) {
+ use_group_key = false;
+ } else if (schm->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACGK &&
+ schm->GetSchemeVersion() == 0x0100) {
+ use_group_key = true;
+ } else {
+ // unsupported scheme
+ return NULL;
+ }
+
+ // find the key
+ const AP4_UI08* key = NULL;
+ AP4_DataBuffer unwrapped_key;
+ if (use_group_key) {
+ const AP4_UI08* group_key = m_KeyMap.GetKey(0);
+ if (group_key == NULL) return NULL; // no group key
+ AP4_ContainerAtom* schi = AP4_DYNAMIC_CAST(AP4_ContainerAtom, sinf->GetChild(AP4_ATOM_TYPE_SCHI));
+ if (schi == NULL) return NULL; // no schi
+ AP4_Atom* gkey = schi->GetChild(AP4_ATOM_TYPE_GKEY);
+ if (gkey == NULL) return NULL; // no gkey
+ AP4_MemoryByteStream* gkey_data = new AP4_MemoryByteStream();
+ gkey->WriteFields(*gkey_data);
+ AP4_AesKeyUnwrap(group_key, gkey_data->GetData(), gkey_data->GetDataSize(), unwrapped_key);
+ key = unwrapped_key.GetData();
+ gkey_data->Release();
+ } else {
+ key = m_KeyMap.GetKey(sinf_entry->m_TrackId);
+ }
+ if (key == NULL) return NULL;
+
+ // create the decrypter
+ AP4_MarlinIpmpTrackDecrypter* decrypter = NULL;
+ AP4_Result result = AP4_MarlinIpmpTrackDecrypter::Create(*m_BlockCipherFactory,
+ key, decrypter);
+ if (AP4_FAILED(result)) return NULL;
+
+ return decrypter;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackDecrypter::Create
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpTrackDecrypter::Create(AP4_BlockCipherFactory& cipher_factory,
+ const AP4_UI08* key,
+ AP4_MarlinIpmpTrackDecrypter*& decrypter)
+{
+ // default value
+ decrypter = NULL;
+
+ // create a block cipher for the decrypter
+ AP4_BlockCipher* block_cipher = NULL;
+ AP4_Result result = cipher_factory.Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::DECRYPT,
+ key,
+ AP4_AES_BLOCK_SIZE,
+ block_cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // create a CBC cipher
+ AP4_CbcStreamCipher* cbc_cipher = new AP4_CbcStreamCipher(block_cipher, AP4_StreamCipher::DECRYPT);
+
+ // create the track decrypter
+ decrypter = new AP4_MarlinIpmpTrackDecrypter(cbc_cipher);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackDecrypter::~AP4_MarlinIpmpTrackDecrypter
++---------------------------------------------------------------------*/
+AP4_MarlinIpmpTrackDecrypter::~AP4_MarlinIpmpTrackDecrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackDecrypter:GetProcessedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_MarlinIpmpTrackDecrypter::GetProcessedSampleSize(AP4_Sample& sample)
+{
+ // with CBC, we need to decrypt the last block to know what the padding was
+ AP4_Size encrypted_size = sample.GetSize()-AP4_AES_BLOCK_SIZE;
+ AP4_DataBuffer encrypted;
+ AP4_DataBuffer decrypted;
+ AP4_Size decrypted_size = AP4_CIPHER_BLOCK_SIZE;
+ if (sample.GetSize() < 2*AP4_CIPHER_BLOCK_SIZE) {
+ return 0;
+ }
+ AP4_Size offset = sample.GetSize()-2*AP4_CIPHER_BLOCK_SIZE;
+ if (AP4_FAILED(sample.ReadData(encrypted, 2*AP4_CIPHER_BLOCK_SIZE, offset))) {
+ return 0;
+ }
+ decrypted.Reserve(decrypted_size);
+ m_Cipher->SetIV(encrypted.GetData());
+ if (AP4_FAILED(m_Cipher->ProcessBuffer(encrypted.GetData()+AP4_CIPHER_BLOCK_SIZE,
+ AP4_CIPHER_BLOCK_SIZE,
+ decrypted.UseData(),
+ &decrypted_size,
+ true))) {
+ return 0;
+ }
+ unsigned int padding_size = AP4_CIPHER_BLOCK_SIZE-decrypted_size;
+ return encrypted_size-padding_size;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackDecrypter:ProcessSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpTrackDecrypter::ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out)
+{
+ AP4_Result result;
+
+ const AP4_UI08* in = data_in.GetData();
+ AP4_Size in_size = data_in.GetDataSize();
+
+ // default to 0 output
+ data_out.SetDataSize(0);
+
+ // check that we have at least the minimum size
+ if (in_size < 2*AP4_AES_BLOCK_SIZE) return AP4_ERROR_INVALID_FORMAT;
+
+ // process the sample data
+ AP4_Size out_size = in_size-AP4_AES_BLOCK_SIZE; // worst case
+ data_out.SetDataSize(out_size);
+ AP4_UI08* out = data_out.UseData();
+
+ // decrypt the data
+ m_Cipher->SetIV(in);
+ result = m_Cipher->ProcessBuffer(in+AP4_AES_BLOCK_SIZE,
+ in_size-AP4_AES_BLOCK_SIZE,
+ out,
+ &out_size,
+ true);
+ if (AP4_FAILED(result)) return result;
+
+ // update the payload size
+ data_out.SetDataSize(out_size);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpEncryptingProcessor::AP4_MarlinIpmpEncryptingProcessor
++---------------------------------------------------------------------*/
+AP4_MarlinIpmpEncryptingProcessor::AP4_MarlinIpmpEncryptingProcessor(
+ bool use_group_key, /* = false */
+ const AP4_ProtectionKeyMap* key_map, /* = NULL */
+ AP4_BlockCipherFactory* block_cipher_factory /* = NULL */) :
+ m_UseGroupKey(use_group_key)
+{
+ if (key_map) {
+ // copy the keys
+ m_KeyMap.SetKeys(*key_map);
+ }
+
+ if (block_cipher_factory == NULL) {
+ m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
+ } else {
+ m_BlockCipherFactory = block_cipher_factory;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpEncryptingProcessor::Initialize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpEncryptingProcessor::Initialize(
+ AP4_AtomParent& top_level,
+ AP4_ByteStream& /*stream*/,
+ AP4_Processor::ProgressListener* /*listener = NULL*/)
+{
+ // get the moov atom
+ AP4_MoovAtom* moov = AP4_DYNAMIC_CAST(AP4_MoovAtom, top_level.GetChild(AP4_ATOM_TYPE_MOOV));
+ if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // deal with the file type
+ AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
+ if (ftyp) {
+ // remove the atom, it will be replaced with a new one
+ top_level.RemoveChild(ftyp);
+
+ // keep the existing brand and compatible brands
+ AP4_Array<AP4_UI32> compatible_brands;
+ compatible_brands.EnsureCapacity(ftyp->GetCompatibleBrands().ItemCount()+1);
+ for (unsigned int i=0; i<ftyp->GetCompatibleBrands().ItemCount(); i++) {
+ compatible_brands.Append(ftyp->GetCompatibleBrands()[i]);
+ }
+
+ // add the MGSV compatible brand if it is not already there
+ if (!ftyp->HasCompatibleBrand(AP4_MARLIN_BRAND_MGSV)) {
+ compatible_brands.Append(AP4_MARLIN_BRAND_MGSV);
+ }
+
+ // create a replacement for the major brand
+ AP4_FtypAtom* new_ftyp = new AP4_FtypAtom(AP4_MARLIN_BRAND_MGSV,
+ 0x13c078c, //AP4_MARLIN_BRAND_MGSV_MAJOR_VERSION,
+ &compatible_brands[0],
+ compatible_brands.ItemCount());
+ delete ftyp;
+ ftyp = new_ftyp;
+ } else {
+ AP4_UI32 isom = AP4_FTYP_BRAND_ISOM;
+ ftyp = new AP4_FtypAtom(AP4_MARLIN_BRAND_MGSV, 0, &isom, 1);
+ }
+
+ // insert the ftyp atom as the first child
+ top_level.AddChild(ftyp, 0);
+
+ // create and 'mpod' track reference atom
+ AP4_TrefTypeAtom* mpod = new AP4_TrefTypeAtom(AP4_ATOM_TYPE_MPOD);
+
+ // look for an available track ID, starting at 1
+ unsigned int od_track_id = 0;
+ unsigned int od_track_position = 0;
+ for (AP4_List<AP4_TrakAtom>::Item* trak_item = moov->GetTrakAtoms().FirstItem();
+ trak_item;
+ trak_item = trak_item->GetNext()) {
+ AP4_TrakAtom* trak = trak_item->GetData();
+ if (trak) {
+ od_track_position++;
+ if (trak->GetId() >= od_track_id) {
+ od_track_id = trak->GetId()+1;
+ }
+
+ // if the track is encrypted, reference it in the mpod
+ if (m_KeyMap.GetKey(trak->GetId())) {
+ mpod->AddTrackId(trak->GetId());
+ }
+
+ //m_SinfEntries.Add(new SinfEntry(trak->GetId(), NULL));
+ }
+ }
+
+ // check that there was at least one track in the file
+ if (od_track_id == 0) return AP4_ERROR_INVALID_FORMAT;
+
+ // create an initial object descriptor
+ AP4_InitialObjectDescriptor* iod =
+ // FIXME: get real values from the property map
+ new AP4_InitialObjectDescriptor(AP4_DESCRIPTOR_TAG_MP4_IOD,
+ 1022, // object descriptor id
+ false,
+ 0xFE, // OD profile level (0xFE = No OD profile specified)
+ 0xFF, // scene profile level
+ 0xFE, // audio profile level
+ 0xFE, // visual profile level
+ 0xFF); // graphics profile
+
+ // create an ES_ID_Inc subdescriptor and add it to the initial object descriptor
+ AP4_EsIdIncDescriptor* es_id_inc = new AP4_EsIdIncDescriptor(od_track_id);
+ iod->AddSubDescriptor(es_id_inc);
+
+ // create an iods atom to hold the initial object descriptor
+ AP4_IodsAtom* iods = new AP4_IodsAtom(iod);
+
+ // add the iods atom to the moov atom (try to put it just after mvhd)
+ int iods_position = 0;
+ int item_position = 0;
+ for (AP4_List<AP4_Atom>::Item* moov_item = moov->GetChildren().FirstItem();
+ moov_item;
+ moov_item = moov_item->GetNext()) {
+ ++item_position;
+ if (moov_item->GetData()->GetType() == AP4_ATOM_TYPE_MVHD) {
+ iods_position = item_position;
+ break;
+ }
+ }
+ AP4_Result result = moov->AddChild(iods, iods_position);
+ if (AP4_FAILED(result)) {
+ delete iods;
+ return result;
+ }
+
+ // create a sample table for the OD track
+ AP4_SyntheticSampleTable* od_sample_table = new AP4_SyntheticSampleTable();
+
+ // create the sample description for the OD track
+ AP4_MpegSystemSampleDescription* od_sample_description;
+ od_sample_description = new AP4_MpegSystemSampleDescription(AP4_STREAM_TYPE_OD,
+ AP4_OTI_MPEG4_SYSTEM,
+ NULL,
+ 32768, // buffer size
+ 1024, // max bitrate
+ 512); // avg bitrate
+ od_sample_table->AddSampleDescription(od_sample_description, true);
+
+ // create the OD descriptor update
+ AP4_DescriptorUpdateCommand od_update(AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_UPDATE);
+ for (unsigned int i=0; i<mpod->GetTrackIds().ItemCount(); i++) {
+ AP4_ObjectDescriptor* od = new AP4_ObjectDescriptor(AP4_DESCRIPTOR_TAG_MP4_OD, 256+i); // descriptor id = 256+i
+ od->AddSubDescriptor(new AP4_EsIdRefDescriptor(i+1)); // index into mpod (1-based)
+ od->AddSubDescriptor(new AP4_IpmpDescriptorPointer(i+1)); // descriptor id = i+1
+ od_update.AddDescriptor(od);
+ }
+
+ // create the IPMP descriptor update
+ AP4_DescriptorUpdateCommand ipmp_update(AP4_COMMAND_TAG_IPMP_DESCRIPTOR_UPDATE);
+ for (unsigned int i=0; i<mpod->GetTrackIds().ItemCount(); i++) {
+ // create the ipmp descriptor
+ AP4_IpmpDescriptor* ipmp_descriptor = new AP4_IpmpDescriptor(i+1, AP4_MARLIN_IPMPS_TYPE_MGSV);
+
+ // create the sinf container
+ AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF);
+
+ // add the scheme type atom
+ sinf->AddChild(new AP4_SchmAtom(m_UseGroupKey?
+ AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACGK:
+ AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACBC,
+ 0x0100, NULL, true));
+
+ // create the 'schi' container
+ AP4_ContainerAtom* schi = new AP4_ContainerAtom(AP4_ATOM_TYPE_SCHI);
+
+ // add the content ID
+ const char* content_id = m_PropertyMap.GetProperty(mpod->GetTrackIds()[i], "ContentId");
+ if (content_id) {
+ // add the content ID (8id_)
+ schi->AddChild(new AP4_NullTerminatedStringAtom(AP4_ATOM_TYPE_8ID_, content_id));
+ }
+
+ // add the signed attributes, if any
+ const char* signed_attributes = m_PropertyMap.GetProperty(mpod->GetTrackIds()[i], "SignedAttributes");
+ if (signed_attributes) {
+ // decode the hex-encoded data
+ unsigned int size = (unsigned int)AP4_StringLength(signed_attributes)/2;
+ AP4_DataBuffer attributes_atoms;
+ attributes_atoms.SetDataSize(size);
+ if (AP4_SUCCEEDED(AP4_ParseHex(signed_attributes, attributes_atoms.UseData(), size))) {
+ // parse all the atoms encoded in the data and add them to the 'schi' container
+ AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream(attributes_atoms.GetData(),
+ attributes_atoms.GetDataSize());
+ do {
+ AP4_Atom* atom = NULL;
+ result = AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*mbs, atom);
+ if (AP4_SUCCEEDED(result) && atom) {
+ schi->AddChild(atom);
+ }
+ } while (AP4_SUCCEEDED(result));
+ mbs->Release();
+ }
+ }
+
+ // find what the track type is (necessary for the next step) and the key
+ const AP4_UI08* key;
+ unsigned int key_size = 0;
+ AP4_Track::Type track_type = AP4_Track::TYPE_UNKNOWN;
+ for (AP4_List<AP4_TrakAtom>::Item* trak_item = moov->GetTrakAtoms().FirstItem();
+ trak_item;
+ trak_item = trak_item->GetNext()) {
+ AP4_TrakAtom* trak = trak_item->GetData();
+ if (trak->GetId() == mpod->GetTrackIds()[i]) {
+ // find the handler type
+ AP4_Atom* sub = trak->FindChild("mdia/hdlr");
+ if (sub) {
+ AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, sub);
+ if (hdlr) {
+ AP4_UI32 type = hdlr->GetHandlerType();
+ if (type == AP4_HANDLER_TYPE_SOUN) {
+ track_type = AP4_Track::TYPE_AUDIO;
+ } else if (type == AP4_HANDLER_TYPE_VIDE) {
+ track_type = AP4_Track::TYPE_VIDEO;
+ }
+ }
+ }
+
+ // find the key
+ const AP4_UI08* iv = NULL;
+ if (AP4_SUCCEEDED(m_KeyMap.GetKeyAndIv(trak->GetId(), key, iv))) {
+ key_size = 16;
+ }
+
+ break;
+ }
+ }
+
+ // group key
+ if (m_UseGroupKey) {
+ // find the group key
+ const AP4_UI08* iv = NULL;
+ const AP4_UI08* group_key;
+ if (AP4_SUCCEEDED(m_KeyMap.GetKeyAndIv(0, group_key, iv))) {
+ AP4_DataBuffer wrapped_key;
+ result = AP4_AesKeyWrap(group_key, key, key_size, wrapped_key);
+ if (AP4_FAILED(result)) return result;
+ AP4_UnknownAtom* gkey = new AP4_UnknownAtom(AP4_ATOM_TYPE_GKEY,
+ wrapped_key.GetData(),
+ wrapped_key.GetDataSize());
+ schi->AddChild(gkey);
+ }
+ }
+
+ // create and add the secure attributes (satr)
+ if (track_type != AP4_Track::TYPE_UNKNOWN && key != NULL && key_size != 0) {
+ AP4_ContainerAtom* satr = new AP4_ContainerAtom(AP4_ATOM_TYPE_SATR);
+ switch (track_type) {
+ case AP4_Track::TYPE_AUDIO:
+ satr->AddChild(new AP4_NullTerminatedStringAtom(AP4_ATOM_TYPE_STYP, AP4_MARLIN_IPMP_STYP_AUDIO));
+ break;
+ case AP4_Track::TYPE_VIDEO:
+ satr->AddChild(new AP4_NullTerminatedStringAtom(AP4_ATOM_TYPE_STYP, AP4_MARLIN_IPMP_STYP_VIDEO));
+ break;
+ default:
+ break;
+ }
+
+ // compute the hmac
+ AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream();
+ satr->Write(*mbs);
+ AP4_Hmac* digester = NULL;
+ AP4_Hmac::Create(AP4_Hmac::SHA256, key, key_size, digester);
+ digester->Update(mbs->GetData(), mbs->GetDataSize());
+ AP4_DataBuffer hmac_value;
+ digester->Final(hmac_value);
+ AP4_Atom* hmac = new AP4_UnknownAtom(AP4_ATOM_TYPE_HMAC, hmac_value.GetData(), hmac_value.GetDataSize());
+
+ schi->AddChild(satr);
+ schi->AddChild(hmac);
+
+ mbs->Release();
+ }
+
+ sinf->AddChild(schi);
+
+ // serialize the sinf atom to a buffer and set it as the ipmp data
+ AP4_MemoryByteStream* sinf_data = new AP4_MemoryByteStream((AP4_Size)sinf->GetSize());
+ sinf->Write(*sinf_data);
+ ipmp_descriptor->SetData(sinf_data->GetData(), sinf_data->GetDataSize());
+ sinf_data->Release();
+
+ ipmp_update.AddDescriptor(ipmp_descriptor);
+ }
+
+ // add the sample with the descriptors and updates
+ AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream();
+ od_update.Write(*sample_data);
+ ipmp_update.Write(*sample_data);
+ od_sample_table->AddSample(*sample_data, 0, sample_data->GetDataSize(), 0, 0, 0, 0, true);
+
+ // create the OD track
+ AP4_TrakAtom* od_track = new AP4_TrakAtom(od_sample_table,
+ AP4_HANDLER_TYPE_ODSM,
+ "Bento4 Marlin OD Handler",
+ od_track_id,
+ 0, 0,
+ 1, 1000, 1, 0, "und",
+ 0, 0);
+
+ // add an entry in the processor's stream table to indicate that the
+ // media data for the OD track is not in the file stream, but in our
+ // memory stream.
+ m_ExternalTrackData.Add(new ExternalTrackData(od_track_id, sample_data));
+ sample_data->Release();
+
+ // add a tref track reference atom
+ AP4_ContainerAtom* tref = new AP4_ContainerAtom(AP4_ATOM_TYPE_TREF);
+ tref->AddChild(mpod);
+ od_track->AddChild(tref, 1); // add after 'tkhd'
+
+ // add the track to the moov atoms (just after the last track)
+ moov->AddChild(od_track, od_track_position);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpEncryptingProcessor::CreateTrackHandler
++---------------------------------------------------------------------*/
+AP4_Processor::TrackHandler*
+AP4_MarlinIpmpEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
+{
+ // create a handler for this track if we have a key for it
+ const AP4_UI08* key;
+ const AP4_UI08* iv;
+ if (AP4_SUCCEEDED(m_KeyMap.GetKeyAndIv(trak->GetId(), key, iv))) {
+ // create the track handler
+ AP4_MarlinIpmpTrackEncrypter* handler = NULL;
+ AP4_Result result = AP4_MarlinIpmpTrackEncrypter::Create(*m_BlockCipherFactory, key, iv, handler);
+ if (AP4_FAILED(result)) return NULL;
+ return handler;
+ }
+
+ // not encrypted
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackEncrypter::Create
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpTrackEncrypter::Create(AP4_BlockCipherFactory& cipher_factory,
+ const AP4_UI08* key,
+ const AP4_UI08* iv,
+ AP4_MarlinIpmpTrackEncrypter*& encrypter)
+{
+ // default value
+ encrypter = NULL;
+
+ // create a block cipher
+ AP4_BlockCipher* block_cipher = NULL;
+ AP4_Result result = cipher_factory.Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::ENCRYPT,
+ key,
+ AP4_AES_BLOCK_SIZE,
+ block_cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // create a CBC cipher
+ AP4_CbcStreamCipher* cbc_cipher = new AP4_CbcStreamCipher(block_cipher, AP4_StreamCipher::ENCRYPT);
+
+ // create the track encrypter
+ encrypter = new AP4_MarlinIpmpTrackEncrypter(cbc_cipher, iv);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackEncrypter::AP4_MarlinIpmpTrackEncrypter
++---------------------------------------------------------------------*/
+AP4_MarlinIpmpTrackEncrypter::AP4_MarlinIpmpTrackEncrypter(AP4_StreamCipher* cipher,
+ const AP4_UI08* iv) :
+ m_Cipher(cipher)
+{
+ // copy the IV
+ AP4_CopyMemory(m_IV, iv, AP4_AES_BLOCK_SIZE);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackEncrypter::~AP4_MarlinIpmpTrackEncrypter
++---------------------------------------------------------------------*/
+AP4_MarlinIpmpTrackEncrypter::~AP4_MarlinIpmpTrackEncrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackEncrypter:GetProcessedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_MarlinIpmpTrackEncrypter::GetProcessedSampleSize(AP4_Sample& sample)
+{
+ return AP4_CIPHER_BLOCK_SIZE*(2+(sample.GetSize()/AP4_CIPHER_BLOCK_SIZE));
+}
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackEncrypter:ProcessSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MarlinIpmpTrackEncrypter::ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out)
+{
+ AP4_Result result;
+
+ const AP4_UI08* in = data_in.GetData();
+ AP4_Size in_size = data_in.GetDataSize();
+
+ // default to 0 output
+ data_out.SetDataSize(0);
+
+ // process the sample data
+ AP4_Size out_size = AP4_CIPHER_BLOCK_SIZE*(2+(in_size/AP4_CIPHER_BLOCK_SIZE));
+ data_out.SetDataSize(out_size);
+ AP4_UI08* out = data_out.UseData();
+
+ // write the IV
+ AP4_CopyMemory(out, m_IV, AP4_CIPHER_BLOCK_SIZE);
+ out_size -= AP4_CIPHER_BLOCK_SIZE;
+
+ // encrypt the data
+ m_Cipher->SetIV(m_IV);
+ result = m_Cipher->ProcessBuffer(in,
+ in_size,
+ out+AP4_AES_BLOCK_SIZE,
+ &out_size,
+ true);
+ if (AP4_FAILED(result)) return result;
+
+ // update the payload size
+ data_out.SetDataSize(out_size+AP4_AES_BLOCK_SIZE);
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Marlin.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Marlin.h new file mode 100644 index 000000000..7e1b428d6 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Marlin.h @@ -0,0 +1,203 @@ +/*****************************************************************
+|
+| AP4 - Marlin File Format support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+#ifndef _AP4_MARLIN_H_
+#define _AP4_MARLIN_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4SampleEntry.h"
+#include "Ap4Atom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4SampleDescription.h"
+#include "Ap4Processor.h"
+#include "Ap4Protection.h"
+#include "Ap4TrefTypeAtom.h"
+#include "Ap4ObjectDescriptor.h"
+#include "Ap4Command.h"
+#include "Ap4UuidAtom.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_UI32 AP4_MARLIN_BRAND_MGSV = AP4_ATOM_TYPE('M','G','S','V');
+const AP4_UI16 AP4_MARLIN_IPMPS_TYPE_MGSV = 0xA551;
+const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACBC = AP4_ATOM_TYPE('A','C','B','C');
+const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACGK = AP4_ATOM_TYPE('A','C','G','K');
+
+const AP4_Atom::Type AP4_ATOM_TYPE_SATR = AP4_ATOM_TYPE('s','a','t','r');
+const AP4_Atom::Type AP4_ATOM_TYPE_STYP = AP4_ATOM_TYPE('s','t','y','p');
+const AP4_Atom::Type AP4_ATOM_TYPE_HMAC = AP4_ATOM_TYPE('h','m','a','c');
+const AP4_Atom::Type AP4_ATOM_TYPE_GKEY = AP4_ATOM_TYPE('g','k','e','y');
+
+const char* const AP4_MARLIN_IPMP_STYP_VIDEO = "urn:marlin:organization:sne:content-type:video";
+const char* const AP4_MARLIN_IPMP_STYP_AUDIO = "urn:marlin:organization:sne:content-type:audio";
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpParser
++---------------------------------------------------------------------*/
+class AP4_MarlinIpmpParser
+{
+public:
+ // types
+ struct SinfEntry {
+ SinfEntry(AP4_UI32 track_id, AP4_ContainerAtom* sinf) :
+ m_TrackId(track_id), m_Sinf(sinf) {}
+ ~SinfEntry() { delete m_Sinf; }
+ AP4_UI32 m_TrackId;
+ AP4_ContainerAtom* m_Sinf;
+ };
+
+ // methods
+ static AP4_Result Parse(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ AP4_List<SinfEntry>& sinf_entries,
+ bool remove_od_data=false);
+
+private:
+ AP4_MarlinIpmpParser() {} // this class can't be instantiated
+};
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpDecryptingProcessor
++---------------------------------------------------------------------*/
+class AP4_MarlinIpmpDecryptingProcessor : public AP4_Processor
+{
+public:
+ // constructor and destructor
+ AP4_MarlinIpmpDecryptingProcessor(const AP4_ProtectionKeyMap* key_map = NULL,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+ ~AP4_MarlinIpmpDecryptingProcessor();
+
+ // accessors
+ AP4_ProtectionKeyMap& GetKeyMap() { return m_KeyMap; }
+
+ // methods
+ virtual AP4_Result Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ ProgressListener* listener);
+ virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
+
+private:
+
+ // members
+ AP4_BlockCipherFactory* m_BlockCipherFactory;
+ AP4_ProtectionKeyMap m_KeyMap;
+ AP4_List<AP4_MarlinIpmpParser::SinfEntry> m_SinfEntries;
+};
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackDecrypter
++---------------------------------------------------------------------*/
+class AP4_MarlinIpmpTrackDecrypter : public AP4_Processor::TrackHandler
+{
+public:
+ // class methods
+ static AP4_Result Create(AP4_BlockCipherFactory& cipher_factory,
+ const AP4_UI08* key,
+ AP4_MarlinIpmpTrackDecrypter*& decrypter);
+
+ // destructor
+ ~AP4_MarlinIpmpTrackDecrypter();
+
+ // AP4_Processor::TrackHandler methods
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample);
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out);
+
+
+private:
+ // constructor
+ AP4_MarlinIpmpTrackDecrypter(AP4_StreamCipher* cipher) : m_Cipher(cipher) {}
+
+ // members
+ AP4_StreamCipher* m_Cipher;
+};
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpEncryptingProcessor
++---------------------------------------------------------------------*/
+class AP4_MarlinIpmpEncryptingProcessor : public AP4_Processor
+{
+public:
+ // constructor
+ AP4_MarlinIpmpEncryptingProcessor(bool use_group_key = false,
+ const AP4_ProtectionKeyMap* key_map = NULL,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+
+ // accessors
+ AP4_ProtectionKeyMap& GetKeyMap() { return m_KeyMap; }
+ AP4_TrackPropertyMap& GetPropertyMap() { return m_PropertyMap; }
+
+ // AP4_Processor methods
+ virtual AP4_Result Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ AP4_Processor::ProgressListener* listener = NULL);
+ virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
+
+private:
+ // members
+ AP4_BlockCipherFactory* m_BlockCipherFactory;
+ bool m_UseGroupKey;
+ AP4_ProtectionKeyMap m_KeyMap;
+ AP4_TrackPropertyMap m_PropertyMap;
+};
+
+/*----------------------------------------------------------------------
+| AP4_MarlinIpmpTrackEncrypter
++---------------------------------------------------------------------*/
+class AP4_MarlinIpmpTrackEncrypter : public AP4_Processor::TrackHandler
+{
+public:
+ // class methods
+ static AP4_Result Create(AP4_BlockCipherFactory& cipher_factory,
+ const AP4_UI08* key,
+ const AP4_UI08* iv,
+ AP4_MarlinIpmpTrackEncrypter*& encrypter);
+
+ // destructor
+ ~AP4_MarlinIpmpTrackEncrypter();
+
+ // AP4_Processor::TrackHandler methods
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample);
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out);
+
+
+private:
+ // constructor
+ AP4_MarlinIpmpTrackEncrypter(AP4_StreamCipher* cipher, const AP4_UI08* iv);
+
+ // members
+ AP4_UI08 m_IV[16];
+ AP4_StreamCipher* m_Cipher;
+};
+
+#endif // _AP4_MARLIN_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MdhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MdhdAtom.cpp new file mode 100644 index 000000000..78bab0b3c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MdhdAtom.cpp @@ -0,0 +1,173 @@ +/***************************************************************** +| +| AP4 - mdhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4MdhdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MdhdAtom) + +/*---------------------------------------------------------------------- +| AP4_MdhdAtom::Create ++---------------------------------------------------------------------*/ +AP4_MdhdAtom* +AP4_MdhdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version > 1) return NULL; + return new AP4_MdhdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_MdhdAtom::AP4_MdhdAtom ++---------------------------------------------------------------------*/ +AP4_MdhdAtom::AP4_MdhdAtom(AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI32 time_scale, + AP4_UI64 duration, + const char* language) : + AP4_Atom(AP4_ATOM_TYPE_MDHD, AP4_FULL_ATOM_HEADER_SIZE+20, 0, 0), + m_CreationTime(creation_time), + m_ModificationTime(modification_time), + m_TimeScale(time_scale), + m_Duration(duration) +{ + m_Language.Assign(language, 3); +} + +/*---------------------------------------------------------------------- +| AP4_MdhdAtom::AP4_MdhdAtom ++---------------------------------------------------------------------*/ +AP4_MdhdAtom::AP4_MdhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_MDHD, size, version, flags) +{ + if (m_Version == 0) { + AP4_UI32 creation_time; + stream.ReadUI32(creation_time); + m_CreationTime = creation_time; + AP4_UI32 modification_time; + stream.ReadUI32(modification_time); + m_ModificationTime = modification_time; + stream.ReadUI32(m_TimeScale); + AP4_UI32 duration; + stream.ReadUI32(duration); + m_Duration = duration; + } else { + stream.ReadUI64(m_CreationTime); + stream.ReadUI64(m_ModificationTime); + stream.ReadUI32(m_TimeScale); + stream.ReadUI64(m_Duration); + } + + unsigned char lang[2]; + stream.Read(lang, 2); + char l0 = ((lang[0]>>2)&0x1F); + char l1 = (((lang[0]&0x3)<<3) | ((lang[1]>>5)&0x7)); + char l2 = ((lang[1]&0x1F)); + if (l0 && l1 && l2) { + char lang_str[3] = {l0+0x60, l1+0x60, l2+0x60}; + m_Language.Assign(lang_str, 3); + } else { + m_Language.Assign("```", 3); + } +} + +/*---------------------------------------------------------------------- +| AP4_MdhdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MdhdAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + if (m_Version == 0) { + result = stream.WriteUI32((AP4_UI32)m_CreationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_ModificationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_TimeScale); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_Duration); + if (AP4_FAILED(result)) return result; + } else { + result = stream.WriteUI64(m_CreationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_ModificationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_TimeScale); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_Duration); + if (AP4_FAILED(result)) return result; + } + + // write the language + AP4_UI08 l0 = m_Language[0]-0x60; + AP4_UI08 l1 = m_Language[1]-0x60; + AP4_UI08 l2 = m_Language[2]-0x60; + result = stream.WriteUI08(l0<<2 | l1>>3); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI08(l1<<5 | l2); + if (AP4_FAILED(result)) return result; + + // pre-defined + return stream.WriteUI16(0); +} + +/*---------------------------------------------------------------------- +| AP4_MdhdAtom::GetDurationMs ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_MdhdAtom::GetDurationMs() +{ + return AP4_DurationMsFromUnits(m_Duration, m_TimeScale); +} + +/*---------------------------------------------------------------------- +| AP4_MdhdAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MdhdAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("timescale", m_TimeScale); + inspector.AddField("duration", m_Duration); + inspector.AddField("duration(ms)", GetDurationMs()); + inspector.AddField("language", m_Language.GetChars()); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MdhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MdhdAtom.h new file mode 100644 index 000000000..f61ba9f6a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MdhdAtom.h @@ -0,0 +1,86 @@ +/***************************************************************** +| +| AP4 - mdhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_MDHD_ATOM_H_ +#define _AP4_MDHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_MDHD_DEFAULT_GENERIC_TIMESCALE = 1000; +const AP4_UI32 AP4_MDHD_DEFAULT_VIDEO_TIMESCALE = 90000; + +/*---------------------------------------------------------------------- +| AP4_MdhdAtom ++---------------------------------------------------------------------*/ +class AP4_MdhdAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_MdhdAtom, AP4_Atom) + + // class methods + static AP4_MdhdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_MdhdAtom(AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI32 time_scale, + AP4_UI64 duration, + const char* language); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + AP4_UI32 GetDurationMs(); + AP4_UI64 GetDuration() { return m_Duration; } + void SetDuration(AP4_UI64 duration) { m_Duration = duration; } + AP4_UI32 GetTimeScale() { return m_TimeScale; } + void SetTimeScale(AP4_UI32 timescale) { m_TimeScale = timescale; } + const AP4_String& GetLanguage() { return m_Language; } + +private: + // methods + AP4_MdhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI64 m_CreationTime; + AP4_UI64 m_ModificationTime; + AP4_UI32 m_TimeScale; + AP4_UI64 m_Duration; + AP4_String m_Language; +}; + +#endif // _AP4_MDHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MehdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MehdAtom.cpp new file mode 100644 index 000000000..cf4ae40ca --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MehdAtom.cpp @@ -0,0 +1,107 @@ +/***************************************************************** +| +| AP4 - mehd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4MehdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MehdAtom) + +/*---------------------------------------------------------------------- +| AP4_MehdAtom::Create ++---------------------------------------------------------------------*/ +AP4_MehdAtom* +AP4_MehdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version > 1) return NULL; + return new AP4_MehdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_MehdAtom::AP4_MehdAtom ++---------------------------------------------------------------------*/ +AP4_MehdAtom::AP4_MehdAtom(AP4_UI64 duration) : + AP4_Atom(AP4_ATOM_TYPE_MEHD, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0), + m_Duration(duration) +{ + if (duration > 0xFFFFFFFF) { + m_Version = 1; + m_Size32 += 4; + } +} + +/*---------------------------------------------------------------------- +| AP4_MehdAtom::AP4_MehdAtom ++---------------------------------------------------------------------*/ +AP4_MehdAtom::AP4_MehdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_MEHD, size, version, flags) +{ + if (m_Version == 0) { + AP4_UI32 duration; + stream.ReadUI32(duration); + m_Duration = duration; + } else { + stream.ReadUI64(m_Duration); + } +} + +/*---------------------------------------------------------------------- +| AP4_MehdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MehdAtom::WriteFields(AP4_ByteStream& stream) +{ + if (m_Version == 0) { + return stream.WriteUI32((AP4_UI32)m_Duration); + } else { + return stream.WriteUI64(m_Duration); + } +} + +/*---------------------------------------------------------------------- +| AP4_MehdAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MehdAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("duration", m_Duration); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MehdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MehdAtom.h new file mode 100644 index 000000000..5d0052920 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MehdAtom.h @@ -0,0 +1,67 @@ +/***************************************************************** +| +| AP4 - mehd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_MEHD_ATOM_H_ +#define _AP4_MEHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4List.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_MehdAtom ++---------------------------------------------------------------------*/ +class AP4_MehdAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_MehdAtom, AP4_Atom) + + // class methods + static AP4_MehdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_MehdAtom(AP4_UI64 duration); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + AP4_UI64 GetDuration() { return m_Duration; } + void SetDuration(AP4_UI64 duration) { m_Duration = duration;} + +private: + // methods + AP4_MehdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI64 m_Duration; +}; + +#endif // _AP4_MEHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfhdAtom.cpp new file mode 100644 index 000000000..62294f74a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfhdAtom.cpp @@ -0,0 +1,93 @@ +/*****************************************************************
+|
+| AP4 - mfhd Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4MfhdAtom.h"
+#include "Ap4Utils.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MfhdAtom)
+
+
+/*----------------------------------------------------------------------
+| AP4_MfhdAtom::Create
++---------------------------------------------------------------------*/
+AP4_MfhdAtom*
+AP4_MfhdAtom::Create(AP4_Size size, AP4_ByteStream& stream)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version > 0) return NULL;
+ return new AP4_MfhdAtom(size, version, flags, stream);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MfhdAtom::AP4_MfhdAtom
++---------------------------------------------------------------------*/
+AP4_MfhdAtom::AP4_MfhdAtom(AP4_UI32 sequence_number) :
+ AP4_Atom(AP4_ATOM_TYPE_MFHD, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0),
+ m_SequenceNumber(sequence_number)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_MfhdAtom::AP4_MfhdAtom
++---------------------------------------------------------------------*/
+AP4_MfhdAtom::AP4_MfhdAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream) :
+ AP4_Atom(AP4_ATOM_TYPE_MFHD, size, version, flags)
+{
+ stream.ReadUI32(m_SequenceNumber);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MfhdAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MfhdAtom::WriteFields(AP4_ByteStream& stream)
+{
+ return stream.WriteUI32(m_SequenceNumber);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MfhdAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MfhdAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("sequence number", m_SequenceNumber);
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfhdAtom.h new file mode 100644 index 000000000..ecdaacb0d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfhdAtom.h @@ -0,0 +1,67 @@ +/*****************************************************************
+|
+| AP4 - mfhd Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_MFHD_ATOM_H_
+#define _AP4_MFHD_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+
+/*----------------------------------------------------------------------
+| AP4_MfhdAtom
++---------------------------------------------------------------------*/
+class AP4_MfhdAtom : public AP4_Atom
+{
+public:
+ AP4_IMPLEMENT_DYNAMIC_CAST(AP4_MfhdAtom)
+
+ // class methods
+ static AP4_MfhdAtom* Create(AP4_Size size, AP4_ByteStream& stream);
+
+ // methods
+ AP4_MfhdAtom(AP4_UI32 sequence_number);
+ virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
+ virtual AP4_Result WriteFields(AP4_ByteStream& stream);
+
+ AP4_UI32 GetSequenceNumber() { return m_SequenceNumber; }
+ void SetSequenceNumber(AP4_UI32 sequence_number) { m_SequenceNumber = sequence_number; }
+
+private:
+ // methods
+ AP4_MfhdAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream);
+
+ // members
+ AP4_UI32 m_SequenceNumber;
+};
+
+#endif // _AP4_MFHD_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfroAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfroAtom.cpp new file mode 100644 index 000000000..7000bb529 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfroAtom.cpp @@ -0,0 +1,89 @@ +/***************************************************************** +| +| AP4 - tfra Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4MfroAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_MfroAtom::Create ++---------------------------------------------------------------------*/ +AP4_MfroAtom* +AP4_MfroAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version = 0; + AP4_UI32 flags = 0; + AP4_Result result = ReadFullHeader(stream, version, flags); + if (AP4_FAILED(result)) return NULL; + if (version != 0) return NULL; + return new AP4_MfroAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_MfroAtom::AP4_MfroAtom ++---------------------------------------------------------------------*/ +AP4_MfroAtom::AP4_MfroAtom(AP4_UI32 mfra_size) : + AP4_Atom(AP4_ATOM_TYPE_MFRO, AP4_FULL_ATOM_HEADER_SIZE+4), + m_MfraSize(mfra_size) +{ +} + +/*---------------------------------------------------------------------- +| AP4_MfroAtom::AP4_MfroAtom ++---------------------------------------------------------------------*/ +AP4_MfroAtom::AP4_MfroAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_MFRO, size, version, flags) +{ + stream.ReadUI32(m_MfraSize); +} + +/*---------------------------------------------------------------------- +| AP4_MfroAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MfroAtom::WriteFields(AP4_ByteStream& stream) +{ + return stream.WriteUI32(m_MfraSize); +} + +/*---------------------------------------------------------------------- +| AP4_MfroAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MfroAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("mfra_size", m_MfraSize); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfroAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfroAtom.h new file mode 100644 index 000000000..82ab1d867 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MfroAtom.h @@ -0,0 +1,71 @@ +/***************************************************************** +| +| AP4 - mfro Atoms +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_MFRO_ATOM_H_ +#define _AP4_MFRO_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_MfroAtom ++---------------------------------------------------------------------*/ +class AP4_MfroAtom : public AP4_Atom +{ +public: + // class methods + static AP4_MfroAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // constructors + AP4_MfroAtom(AP4_UI32 mfra_size); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetMfraSize() { return m_MfraSize; } + +private: + // methods + AP4_MfroAtom(AP4_UI32 size, AP4_UI32 version, AP4_UI32 flags, AP4_ByteStream& stream); + + // members + AP4_UI32 m_MfraSize; +}; + +#endif // _AP4_MFRO_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MoovAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MoovAtom.cpp new file mode 100644 index 000000000..a50080cf1 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MoovAtom.cpp @@ -0,0 +1,220 @@ +/***************************************************************** +| +| AP4 - moov Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4MoovAtom.h" +#include "Ap4TrakAtom.h" +#include "Ap4AtomFactory.h" + +// ==> Start patch MPC +#include "AP4DcomAtom.h" +#include "AP4CmvdAtom.h" +#include "../../../../../../zlib/zlib.h" +// <== End patch MPC + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MoovAtom) + +/*---------------------------------------------------------------------- +| AP4_TrakAtomCollector ++---------------------------------------------------------------------*/ +class AP4_TrakAtomCollector : public AP4_List<AP4_Atom>::Item::Operator +{ +public: + AP4_TrakAtomCollector(AP4_List<AP4_TrakAtom>* track_atoms) : + m_TrakAtoms(track_atoms) {} + + AP4_Result Action(AP4_Atom* atom) const { + if (atom->GetType() == AP4_ATOM_TYPE_TRAK) { + AP4_TrakAtom* trak = AP4_DYNAMIC_CAST(AP4_TrakAtom, atom); + if (trak) { + m_TrakAtoms->Add(trak); + } + } + return AP4_SUCCESS; + } + +private: + AP4_List<AP4_TrakAtom>* m_TrakAtoms; +}; + +/*---------------------------------------------------------------------- +| AP4_MoovAtom::AP4_MoovAtom ++---------------------------------------------------------------------*/ +AP4_MoovAtom::AP4_MoovAtom() : + AP4_ContainerAtom(AP4_ATOM_TYPE_MOOV), + m_TimeScale(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_MoovAtom::AP4_MoovAtom ++---------------------------------------------------------------------*/ +AP4_MoovAtom::AP4_MoovAtom(AP4_UI32 size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_ContainerAtom(AP4_ATOM_TYPE_MOOV, size, false, stream, atom_factory), + m_TimeScale(0) +{ + // ==> Start patch MPC + if(AP4_ContainerAtom* cmov = dynamic_cast<AP4_ContainerAtom*>(GetChild(AP4_ATOM_TYPE_CMOV))) + { + AP4_DcomAtom* dcom = dynamic_cast<AP4_DcomAtom*>(cmov->GetChild(AP4_ATOM_TYPE_DCOM));
+ AP4_CmvdAtom* cmvd = dynamic_cast<AP4_CmvdAtom*>(cmov->GetChild(AP4_ATOM_TYPE_CMVD));
+ if(dcom && dcom->GetCompressorSubType() == AP4_ATOM_TYPE('z','l','i','b') && cmvd)
+ {
+ const AP4_DataBuffer& data = cmvd->GetDataBuffer();
+
+ z_stream d_stream;
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ int res;
+
+ if(Z_OK == (res = inflateInit(&d_stream)))
+ {
+ d_stream.next_in = (Bytef*)data.GetData();
+ d_stream.avail_in = data.GetDataSize();
+
+ unsigned char* dst = NULL;
+ int n = 0;
+
+ do
+ {
+ dst = (unsigned char*)realloc(dst, ++n*1000);
+ d_stream.next_out = &dst[(n-1)*1000];
+ d_stream.avail_out = 1000;
+
+ if(Z_OK != (res = inflate(&d_stream, Z_NO_FLUSH)) && Z_STREAM_END != res)
+ {
+ free(dst);
+ dst = NULL;
+ break;
+ }
+ }
+ while(0 == d_stream.avail_out && 0 != d_stream.avail_in && Z_STREAM_END != res);
+
+ inflateEnd(&d_stream);
+
+ if(dst)
+ {
+ AP4_ByteStream* s = new AP4_MemoryByteStream(dst, d_stream.total_out);
+ ReadChildren(atom_factory, *s, d_stream.total_out);
+ s->Release();
+ free(dst);
+ }
+
+ if(AP4_MoovAtom* moov = dynamic_cast<AP4_MoovAtom*>(GetChild(AP4_ATOM_TYPE_MOOV)))
+ {
+ AP4_List<AP4_Atom> Children;
+
+ for(AP4_List<AP4_Atom>::Item* item = moov->GetChildren().FirstItem();
+ item;
+ item = item->GetNext())
+ {
+ Children.Add(item->GetData());
+ }
+
+ for(AP4_List<AP4_Atom>::Item* item = Children.FirstItem();
+ item;
+ item = item->GetNext())
+ {
+ AP4_Atom* atom = item->GetData();
+ atom->Detach();
+ atom->SetParent(this);
+ m_Children.Add(atom);
+ }
+
+ moov->Detach();
+ delete moov;
+ }
+ }
+ }
+ }
+ // <== End patch MPC
+ + // collect all trak atoms + m_Children.Apply(AP4_TrakAtomCollector(&m_TrakAtoms)); +} + +/*---------------------------------------------------------------------- +| AP4_MoovAtom::AdjustChunkOffsets ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MoovAtom::AdjustChunkOffsets(AP4_SI64 offset) +{ + for (AP4_List<AP4_TrakAtom>::Item* item = m_TrakAtoms.FirstItem(); + item; + item = item->GetNext()) { + AP4_TrakAtom* trak = item->GetData(); + trak->AdjustChunkOffsets(offset); + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_MoovAtom::OnChildAdded ++---------------------------------------------------------------------*/ +void +AP4_MoovAtom::OnChildAdded(AP4_Atom* atom) +{ + // keep the atom in the list of trak atoms + if (atom->GetType() == AP4_ATOM_TYPE_TRAK) { + AP4_TrakAtom* trak = AP4_DYNAMIC_CAST(AP4_TrakAtom, atom); + if (trak) { + m_TrakAtoms.Add(trak); + } + } + + // call the base class implementation + AP4_ContainerAtom::OnChildAdded(atom); +} + +/*---------------------------------------------------------------------- +| AP4_MoovAtom::OnChildRemoved ++---------------------------------------------------------------------*/ +void +AP4_MoovAtom::OnChildRemoved(AP4_Atom* atom) +{ + // remove the atom from the list of trak atoms + if (atom->GetType() == AP4_ATOM_TYPE_TRAK) { + AP4_TrakAtom* trak = AP4_DYNAMIC_CAST(AP4_TrakAtom, atom); + if (trak) { + m_TrakAtoms.Remove(trak); + } + } + + // call the base class implementation + AP4_ContainerAtom::OnChildRemoved(atom); +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MoovAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MoovAtom.h new file mode 100644 index 000000000..f06b2a137 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MoovAtom.h @@ -0,0 +1,84 @@ +/***************************************************************** +| +| AP4 - moov Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_MOOV_ATOM_H_ +#define _AP4_MOOV_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4List.h" +#include "Ap4ContainerAtom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_AtomFactory; +class AP4_TrakAtom; + +/*---------------------------------------------------------------------- +| AP4_MoovAtom ++---------------------------------------------------------------------*/ +class AP4_MoovAtom : public AP4_ContainerAtom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_MoovAtom, AP4_ContainerAtom) + + // class methods + static AP4_MoovAtom* Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) { + return new AP4_MoovAtom(size, stream, atom_factory); + } + + // methods + AP4_MoovAtom(); + AP4_List<AP4_TrakAtom>& GetTrakAtoms() { + return m_TrakAtoms; + } + AP4_UI32 GetTimeScale() { + return m_TimeScale; + } + AP4_Result AdjustChunkOffsets(AP4_SI64 offset); + + // AP4_AtomParent methods + void OnChildAdded(AP4_Atom* atom); + void OnChildRemoved(AP4_Atom* atom); + +private: + // methods + AP4_MoovAtom(AP4_UI32 size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // members + AP4_List<AP4_TrakAtom> m_TrakAtoms; + AP4_UI32 m_TimeScale; +}; + +#endif // _AP4_MOOV_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Movie.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Movie.cpp new file mode 100644 index 000000000..57c8c3c50 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Movie.cpp @@ -0,0 +1,237 @@ +/*****************************************************************
+|
+| AP4 - Movie
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4File.h"
+#include "Ap4Atom.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4MoovAtom.h"
+#include "Ap4MvhdAtom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4Movie.h"
+#include "Ap4MetaData.h"
+
+/*----------------------------------------------------------------------
+| AP4_TrackFinderById
++---------------------------------------------------------------------*/
+class AP4_TrackFinderById : public AP4_List<AP4_Track>::Item::Finder
+{
+public:
+ AP4_TrackFinderById(AP4_UI32 track_id) : m_TrackId(track_id) {}
+ AP4_Result Test(AP4_Track* track) const {
+ return track->GetId() == m_TrackId ? AP4_SUCCESS : AP4_FAILURE;
+ }
+private:
+ AP4_UI32 m_TrackId;
+};
+
+/*----------------------------------------------------------------------
+| AP4_TrackFinderByType
++---------------------------------------------------------------------*/
+class AP4_TrackFinderByType : public AP4_List<AP4_Track>::Item::Finder
+{
+public:
+ AP4_TrackFinderByType(AP4_Track::Type type, AP4_Ordinal index = 0) :
+ m_Type(type), m_Index(index) {}
+ AP4_Result Test(AP4_Track* track) const {
+ if (track->GetType() == m_Type && m_Index-- == 0) {
+ return AP4_SUCCESS;
+ } else {
+ return AP4_FAILURE;
+ }
+ }
+private:
+ AP4_Track::Type m_Type;
+ mutable AP4_Ordinal m_Index;
+};
+
+/*----------------------------------------------------------------------
+| AP4_Movie::AP4_Movie
++---------------------------------------------------------------------*/
+AP4_Movie::AP4_Movie(AP4_UI32 time_scale) :
+ m_MoovAtomIsOwned(true)
+{
+ m_MoovAtom = new AP4_MoovAtom();
+ m_MvhdAtom = new AP4_MvhdAtom(0, 0,
+ time_scale,
+ 0,
+ 0x00010000,
+ 0x0100);
+ m_MoovAtom->AddChild(m_MvhdAtom);
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::AP4_Moovie
++---------------------------------------------------------------------*/
+AP4_Movie::AP4_Movie(AP4_MoovAtom* moov, AP4_ByteStream& sample_stream, bool transfer_moov_ownership) :
+ m_MoovAtom(moov),
+ m_MoovAtomIsOwned(transfer_moov_ownership)
+{
+ // ignore null atoms
+ if (moov == NULL) return;
+
+ // get the time scale
+ AP4_UI32 time_scale;
+ m_MvhdAtom = AP4_DYNAMIC_CAST(AP4_MvhdAtom, moov->GetChild(AP4_ATOM_TYPE_MVHD));
+ if (m_MvhdAtom) {
+ time_scale = m_MvhdAtom->GetTimeScale();
+ } else {
+ time_scale = 0;
+ }
+
+ // get all tracks
+ AP4_List<AP4_TrakAtom>* trak_atoms;
+ trak_atoms = &moov->GetTrakAtoms();
+ AP4_List<AP4_TrakAtom>::Item* item = trak_atoms->FirstItem();
+ while (item) {
+ AP4_Track* track = new AP4_Track(*item->GetData(),
+ sample_stream,
+ time_scale);
+ m_Tracks.Add(track);
+ item = item->GetNext();
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::~AP4_Movie
++---------------------------------------------------------------------*/
+AP4_Movie::~AP4_Movie()
+{
+ m_Tracks.DeleteReferences();
+ if (m_MoovAtomIsOwned) delete m_MoovAtom;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::Inspect
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_Movie::Inspect(AP4_AtomInspector& inspector)
+{
+ // dump the moov atom
+ return m_MoovAtom->Inspect(inspector);
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::GetTrack
++---------------------------------------------------------------------*/
+AP4_Track*
+AP4_Movie::GetTrack(AP4_UI32 track_id)
+{
+ AP4_Track* track = NULL;
+ if (AP4_SUCCEEDED(m_Tracks.Find(AP4_TrackFinderById(track_id), track))) {
+ return track;
+ } else {
+ return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::GetTrack
++---------------------------------------------------------------------*/
+AP4_Track*
+AP4_Movie::GetTrack(AP4_Track::Type track_type, AP4_Ordinal index)
+{
+ AP4_Track* track = NULL;
+ if (AP4_SUCCEEDED(m_Tracks.Find(AP4_TrackFinderByType(track_type, index), track))) {
+ return track;
+ } else {
+ return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::AddTrack
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_Movie::AddTrack(AP4_Track* track)
+{
+ // assign an ID to the track unless it already has one
+ if (track->GetId() == 0) {
+ track->SetId(m_Tracks.ItemCount()+1);
+ }
+
+ // if we don't have a time scale, use the one from the track
+ if (m_MvhdAtom->GetTimeScale() == 0) {
+ m_MvhdAtom->SetTimeScale(track->GetMediaTimeScale());
+ }
+
+ // adjust the parent time scale of the track
+ track->SetMovieTimeScale(m_MvhdAtom->GetTimeScale());
+
+ // update the movie duration
+ if (m_MvhdAtom->GetDuration() < track->GetDuration()) {
+ m_MvhdAtom->SetDuration(track->GetDuration());
+ }
+
+ // attach the track as a child
+ track->Attach(m_MoovAtom);
+ m_Tracks.Add(track);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::GetTimeScale
++---------------------------------------------------------------------*/
+AP4_UI32
+AP4_Movie::GetTimeScale()
+{
+ if (m_MvhdAtom) {
+ return m_MvhdAtom->GetTimeScale();
+ } else {
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::GetDuration
++---------------------------------------------------------------------*/
+AP4_UI64
+AP4_Movie::GetDuration()
+{
+ if (m_MvhdAtom) {
+ return m_MvhdAtom->GetDuration();
+ } else {
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_Movie::GetDurationMs
++---------------------------------------------------------------------*/
+AP4_UI32
+AP4_Movie::GetDurationMs()
+{
+ if (m_MvhdAtom) {
+ return m_MvhdAtom->GetDurationMs();
+ } else {
+ return 0;
+ }
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Movie.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Movie.h new file mode 100644 index 000000000..80d6cdb19 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Movie.h @@ -0,0 +1,77 @@ +/***************************************************************** +| +| AP4 - Movie +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_MOVIE_H_ +#define _AP4_MOVIE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4MoovAtom.h" +#include "Ap4MvhdAtom.h" +#include "Ap4Track.h" +#include "Ap4List.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_AtomInspector; +class AP4_MetaData; + +/*---------------------------------------------------------------------- +| AP4_Movie ++---------------------------------------------------------------------*/ +class AP4_Movie { +public: + // methods + AP4_Movie(AP4_UI32 time_scale = 0); + AP4_Movie(AP4_MoovAtom* moov, AP4_ByteStream& sample_stream, bool transfer_moov_ownership = true); + virtual ~AP4_Movie(); + AP4_Result Inspect(AP4_AtomInspector& inspector); + + AP4_MoovAtom* GetMoovAtom() { return m_MoovAtom;} + AP4_MvhdAtom* GetMvhdAtom() { return m_MvhdAtom;} + AP4_List<AP4_Track>& GetTracks() { return m_Tracks; } + AP4_Track* GetTrack(AP4_UI32 track_id); + AP4_Track* GetTrack(AP4_Track::Type type, AP4_Ordinal index = 0); + AP4_Result AddTrack(AP4_Track* track); + AP4_UI32 GetTimeScale(); + AP4_UI64 GetDuration(); + AP4_UI32 GetDurationMs(); + +private: + // members + AP4_MoovAtom* m_MoovAtom; + bool m_MoovAtomIsOwned; + AP4_MvhdAtom* m_MvhdAtom; + AP4_List<AP4_Track> m_Tracks; +}; + +#endif // _AP4_MOVIE_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MovieFragment.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MovieFragment.cpp new file mode 100644 index 000000000..d85bc008b --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MovieFragment.cpp @@ -0,0 +1,179 @@ +/***************************************************************** +| +| AP4 - Movie Fragments +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4File.h" +#include "Ap4Atom.h" +#include "Ap4MfhdAtom.h" +#include "Ap4TfhdAtom.h" +#include "Ap4TrexAtom.h" +#include "Ap4MovieFragment.h" +#include "Ap4ContainerAtom.h" +#include "Ap4FragmentSampleTable.h" +#include "Ap4Movie.h" +#include "Ap4Sample.h" + +/*---------------------------------------------------------------------- +| AP4_MovieFragment::AP4_MovieFragment ++---------------------------------------------------------------------*/ +AP4_MovieFragment::AP4_MovieFragment(AP4_ContainerAtom* moof) : + m_MoofAtom(moof), + m_MfhdAtom(NULL) +{ + if (moof) m_MfhdAtom = AP4_DYNAMIC_CAST(AP4_MfhdAtom, moof->GetChild(AP4_ATOM_TYPE_MFHD)); +} + +/*---------------------------------------------------------------------- +| AP4_MovieFragment::~AP4_MovieFragment ++---------------------------------------------------------------------*/ +AP4_MovieFragment::~AP4_MovieFragment() +{ + delete m_MoofAtom; +} + +/*---------------------------------------------------------------------- +| AP4_MovieFragment::GetSequenceNumber ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_MovieFragment::GetSequenceNumber() +{ + return m_MfhdAtom?m_MfhdAtom->GetSequenceNumber():0; +} + +/*---------------------------------------------------------------------- +| AP4_MovieFragment::GetTrackIds ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MovieFragment::GetTrackIds(AP4_Array<AP4_UI32>& ids) +{ + ids.Clear(); + ids.EnsureCapacity(m_MoofAtom->GetChildren().ItemCount()); + + for (AP4_List<AP4_Atom>::Item* item = m_MoofAtom->GetChildren().FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* atom = item->GetData(); + if (atom->GetType() == AP4_ATOM_TYPE_TRAF) { + AP4_ContainerAtom* traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom); + if (traf) { + AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD)); + if (tfhd) ids.Append(tfhd->GetTrackId()); + } + } + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_MovieFragment::GetTrafAtom ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MovieFragment::GetTrafAtom(AP4_UI32 track_id, AP4_ContainerAtom*& traf) +{ + for (AP4_List<AP4_Atom>::Item* item = m_MoofAtom->GetChildren().FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* atom = item->GetData(); + if (atom->GetType() == AP4_ATOM_TYPE_TRAF) { + traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom); + if (traf) { + AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD)); + if (tfhd && tfhd->GetTrackId() == track_id) { + return AP4_SUCCESS; + } + } + } + } + + // not found + traf = NULL; + return AP4_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| AP4_MovieFragment::CreateSampleTable ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MovieFragment::CreateSampleTable(AP4_MoovAtom* moov, + AP4_UI32 track_id, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position mdat_payload_offset, + AP4_FragmentSampleTable*& sample_table) +{ + // default value + sample_table = NULL; + + // find a trex for this track, if any + AP4_ContainerAtom* mvex = NULL; + AP4_TrexAtom* trex = NULL; + if (moov) { + mvex = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->GetChild(AP4_ATOM_TYPE_MVEX)); + } + if (mvex) { + for (AP4_List<AP4_Atom>::Item* item = mvex->GetChildren().FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* atom = item->GetData(); + if (atom->GetType() == AP4_ATOM_TYPE_TREX) { + trex = AP4_DYNAMIC_CAST(AP4_TrexAtom, atom); + if (trex && trex->GetTrackId() == track_id) break; + trex = NULL; + } + } + } + AP4_ContainerAtom* traf = NULL; + if (AP4_SUCCEEDED(GetTrafAtom(track_id, traf))) { + sample_table = new AP4_FragmentSampleTable(traf, + trex, + sample_stream, + moof_offset, + mdat_payload_offset); + return AP4_SUCCESS; + } + + return AP4_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| AP4_MovieFragment::CreateSampleTable ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MovieFragment::CreateSampleTable(AP4_Movie* movie, + AP4_UI32 track_id, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position mdat_payload_offset, + AP4_FragmentSampleTable*& sample_table) +{ + AP4_MoovAtom* moov = movie?movie->GetMoovAtom():NULL; + return CreateSampleTable(moov, track_id, sample_stream, moof_offset, mdat_payload_offset, sample_table); +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MovieFragment.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MovieFragment.h new file mode 100644 index 000000000..6ff5aae9a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MovieFragment.h @@ -0,0 +1,87 @@ +/***************************************************************** +| +| AP4 - Movie Fragments +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_MOVIE_FRAGMENT_H_ +#define _AP4_MOVIE_FRAGMENT_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4MfhdAtom.h" +#include "Ap4List.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_ContainerAtom; +class AP4_FragmentSampleTable; +class AP4_Movie; +class AP4_MoovAtom; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_FRAG_FLAG_SAMPLE_IS_DIFFERENCE = 0x00010000; + +/*---------------------------------------------------------------------- +| AP4_MovieFragment ++---------------------------------------------------------------------*/ +class AP4_MovieFragment { +public: + // this constructor transfers the ownership of the moof atom to the + // newly constructed object + AP4_MovieFragment(AP4_ContainerAtom* moof); + virtual ~AP4_MovieFragment(); + + AP4_ContainerAtom* GetMoofAtom() { return m_MoofAtom;} + AP4_MfhdAtom* GetMfhdAtom() { return m_MfhdAtom;} + AP4_UI32 GetSequenceNumber(); + AP4_Result GetTrackIds(AP4_Array<AP4_UI32>& ids); + AP4_Result GetTrafAtom(AP4_UI32 track_id, AP4_ContainerAtom*& traf); + AP4_Result CreateSampleTable(AP4_MoovAtom* moov, + AP4_UI32 track_id, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec properly + AP4_FragmentSampleTable*& sample_table); + AP4_Result CreateSampleTable(AP4_Movie* movie, + AP4_UI32 track_id, + AP4_ByteStream* sample_stream, + AP4_Position moof_offset, + AP4_Position mdat_payload_offset, // hack because MS doesn't implement the spec properly + AP4_FragmentSampleTable*& sample_table); + +private: + // members + AP4_ContainerAtom* m_MoofAtom; + AP4_MfhdAtom* m_MfhdAtom; +}; + +#endif // _AP4_MOVIE_FRAGMENT_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Mpeg2Ts.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Mpeg2Ts.cpp new file mode 100644 index 000000000..dbb5f5982 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Mpeg2Ts.cpp @@ -0,0 +1,716 @@ +/***************************************************************** +| +| AP4 - MPEG2 Transport Streams +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Mpeg2Ts.h" +#include "Ap4ByteStream.h" +#include "Ap4Sample.h" +#include "Ap4SampleDescription.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int AP4_MPEG2TS_PACKET_SIZE = 188; +const unsigned int AP4_MPEG2TS_PACKET_PAYLOAD_SIZE = 184; +const unsigned int AP4_MPEG2TS_SYNC_BYTE = 0x47; +const unsigned int AP4_MPEG2TS_PCR_ADAPTATION_SIZE = 6; + +static unsigned char const StuffingBytes[AP4_MPEG2TS_PACKET_SIZE] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF +}; + +/*---------------------------------------------------------------------- +| GetSamplingFrequencyIndex ++---------------------------------------------------------------------*/ +static unsigned int +GetSamplingFrequencyIndex(unsigned int sampling_frequency) +{ + switch (sampling_frequency) { + case 96000: return 0; + case 88200: return 1; + case 64000: return 2; + case 48000: return 3; + case 44100: return 4; + case 32000: return 5; + case 24000: return 6; + case 22050: return 7; + case 16000: return 8; + case 12000: return 9; + case 11025: return 10; + case 8000: return 11; + case 7350: return 12; + default: return 0; + } +} + +/*---------------------------------------------------------------------- +| MakeAdtsHeader ++---------------------------------------------------------------------*/ +static void +MakeAdtsHeader(unsigned char bits[7], + unsigned int frame_size, + unsigned int sampling_frequency_index, + unsigned int channel_configuration) +{ + bits[0] = 0xFF; + bits[1] = 0xF1; // 0xF9 (MPEG2) + bits[2] = 0x40 | (sampling_frequency_index << 2) | (channel_configuration >> 2); + bits[3] = ((channel_configuration&0x3)<<6) | ((frame_size+7) >> 11); + bits[4] = ((frame_size+7) >> 3)&0xFF; + bits[5] = (((frame_size+7) << 5)&0xFF) | 0x1F; + bits[6] = 0xFC; + + /* + 0: syncword 12 always: '111111111111' + 12: ID 1 0: MPEG-4, 1: MPEG-2 + 13: layer 2 always: '00' + 15: protection_absent 1 + 16: profile 2 + 18: sampling_frequency_index 4 + 22: private_bit 1 + 23: channel_configuration 3 + 26: original/copy 1 + 27: home 1 + 28: emphasis 2 only if ID == 0 + + ADTS Variable header: these can change from frame to frame + 28: copyright_identification_bit 1 + 29: copyright_identification_start 1 + 30: aac_frame_length 13 length of the frame including header (in bytes) + 43: adts_buffer_fullness 11 0x7FF indicates VBR + 54: no_raw_data_blocks_in_frame 2 + ADTS Error check + crc_check 16 only if protection_absent == 0 + */ +} + +/*---------------------------------------------------------------------- +| CRC_Table ++---------------------------------------------------------------------*/ +static AP4_UI32 +const CRC_Table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +/*---------------------------------------------------------------------- +| ComputeCRC ++---------------------------------------------------------------------*/ +static AP4_UI32 +ComputeCRC(const unsigned char* data, unsigned int data_size) +{ + AP4_UI32 crc = 0xFFFFFFFF; + + for (unsigned int i=0; i<data_size; i++) { + crc = (crc << 8) ^ CRC_Table[((crc >> 24) ^ *data++) & 0xFF]; + } + + return crc; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::Stream::WritePacketHeader ++---------------------------------------------------------------------*/ +void +AP4_Mpeg2TsWriter::Stream::WritePacketHeader(bool payload_start, + unsigned int& payload_size, + bool with_pcr, + AP4_UI64 pcr, + AP4_ByteStream& output) +{ + unsigned char header[4]; + header[0] = AP4_MPEG2TS_SYNC_BYTE; + header[1] = ((payload_start?1:0)<<6) | (m_PID >> 8); + header[2] = m_PID & 0xFF; + + unsigned int adaptation_field_size = 0; + if (with_pcr) adaptation_field_size += 2+AP4_MPEG2TS_PCR_ADAPTATION_SIZE; + + // clamp the payload size + if (payload_size+adaptation_field_size > AP4_MPEG2TS_PACKET_PAYLOAD_SIZE) { + payload_size = AP4_MPEG2TS_PACKET_PAYLOAD_SIZE-adaptation_field_size; + } + + // adjust the adaptation field to include stuffing if necessary + if (adaptation_field_size+payload_size < AP4_MPEG2TS_PACKET_PAYLOAD_SIZE) { + adaptation_field_size = AP4_MPEG2TS_PACKET_PAYLOAD_SIZE-payload_size; + } + + if (adaptation_field_size == 0) { + // no adaptation field + header[3] = (1<<4) | ((m_ContinuityCounter++)&0x0F); + output.Write(header, 4); + } else { + // adaptation field present + header[3] = (3<<4) | ((m_ContinuityCounter++)&0x0F); + output.Write(header, 4); + + if (adaptation_field_size == 1) { + // just one byte (stuffing) + output.WriteUI08(0); + } else { + // two or more bytes (stuffing and/or PCR) + output.WriteUI08(adaptation_field_size-1); + output.WriteUI08(with_pcr?(1<<4):0); + unsigned int pcr_size = 0; + if (with_pcr) { + pcr_size = AP4_MPEG2TS_PCR_ADAPTATION_SIZE; + AP4_UI64 pcr_base = pcr/300; + AP4_UI32 pcr_ext = (AP4_UI32)(pcr%300); + AP4_BitWriter writer(pcr_size); + writer.Write((AP4_UI32)(pcr_base>>32), 1); + writer.Write((AP4_UI32)pcr_base, 32); + writer.Write(0x3F, 6); + writer.Write(pcr_ext, 9); + output.Write(writer.GetData(), pcr_size); + } + if (adaptation_field_size > 2) { + output.Write(StuffingBytes, adaptation_field_size-pcr_size-2); + } + } + } +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::SampleStream::WritePES ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsWriter::SampleStream::WritePES(const unsigned char* data, + unsigned int data_size, + AP4_UI64 dts, + bool with_dts, + AP4_UI64 pts, + bool with_pcr, + AP4_ByteStream& output) +{ + unsigned int pes_header_size = 14+(with_dts?5:0); + AP4_BitWriter pes_header(pes_header_size); + + pes_header.Write(0x000001, 24); // packet_start_code_prefix + pes_header.Write(m_StreamId, 8); // stream_id + pes_header.Write(m_StreamId == AP4_MPEG2_TS_DEFAULT_STREAM_ID_VIDEO?0:(data_size+pes_header_size-6), 16); // PES_packet_length + pes_header.Write(2, 2); // '01' + pes_header.Write(0, 2); // PES_scrambling_control + pes_header.Write(0, 1); // PES_priority + pes_header.Write(1, 1); // data_alignment_indicator + pes_header.Write(0, 1); // copyright + pes_header.Write(0, 1); // original_or_copy + pes_header.Write(with_dts?3:2, 2); // PTS_DTS_flags + pes_header.Write(0, 1); // ESCR_flag + pes_header.Write(0, 1); // ES_rate_flag + pes_header.Write(0, 1); // DSM_trick_mode_flag + pes_header.Write(0, 1); // additional_copy_info_flag + pes_header.Write(0, 1); // PES_CRC_flag + pes_header.Write(0, 1); // PES_extension_flag + pes_header.Write(pes_header_size-9, 8);// PES_header_data_length + + pes_header.Write(with_dts?3:2, 4); // '0010' or '0011' + pes_header.Write((AP4_UI32)(pts>>30), 3); // PTS[32..30] + pes_header.Write(1, 1); // marker_bit + pes_header.Write((AP4_UI32)(pts>>15), 15); // PTS[29..15] + pes_header.Write(1, 1); // marker_bit + pes_header.Write((AP4_UI32)pts, 15); // PTS[14..0] + pes_header.Write(1, 1); // market_bit + + if (with_dts) { + pes_header.Write(1, 4); // '0001' + pes_header.Write((AP4_UI32)(dts>>30), 3); // DTS[32..30] + pes_header.Write(1, 1); // marker_bit + pes_header.Write((AP4_UI32)(dts>>15), 15); // DTS[29..15] + pes_header.Write(1, 1); // marker_bit + pes_header.Write((AP4_UI32)dts, 15); // DTS[14..0] + pes_header.Write(1, 1); // market_bit + } + + bool first_packet = true; + data_size += pes_header_size; // add size of PES header + while (data_size) { + unsigned int payload_size = data_size; + if (payload_size > AP4_MPEG2TS_PACKET_PAYLOAD_SIZE) payload_size = AP4_MPEG2TS_PACKET_PAYLOAD_SIZE; + + if (first_packet) { + WritePacketHeader(first_packet, payload_size, with_pcr, (with_dts?dts:pts)*300, output); + first_packet = false; + output.Write(pes_header.GetData(), pes_header_size); + output.Write(data, payload_size-pes_header_size); + data += payload_size-pes_header_size; + } else { + WritePacketHeader(first_packet, payload_size, false, 0, output); + output.Write(data, payload_size); + data += payload_size; + } + data_size -= payload_size; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsAudioSampleStream ++---------------------------------------------------------------------*/ +class AP4_Mpeg2TsAudioSampleStream : public AP4_Mpeg2TsWriter::SampleStream +{ +public: + static AP4_Result Create(AP4_UI16 pid, + AP4_UI32 timescale, + AP4_Mpeg2TsWriter::SampleStream*& stream); + AP4_Result WriteSample(AP4_Sample& sample, + AP4_SampleDescription* sample_description, + bool with_pcr, + AP4_ByteStream& output); + +private: + AP4_Mpeg2TsAudioSampleStream(AP4_UI16 pid, AP4_UI32 timescale) : + AP4_Mpeg2TsWriter::SampleStream(pid, + AP4_MPEG2_TS_DEFAULT_STREAM_ID_AUDIO, + AP4_MPEG2_STREAM_TYPE_ISO_IEC_13818_7, + timescale) {} +}; + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsAudioSampleStream::Create ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsAudioSampleStream::Create(AP4_UI16 pid, + AP4_UI32 timescale, + AP4_Mpeg2TsWriter::SampleStream*& stream) +{ + stream = new AP4_Mpeg2TsAudioSampleStream(pid, timescale); + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsAudioSampleStream::WriteSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsAudioSampleStream::WriteSample(AP4_Sample& sample, + AP4_SampleDescription* sample_description, + bool with_pcr, + AP4_ByteStream& output) +{ + // check the sample description + AP4_MpegAudioSampleDescription* audio_desc = AP4_DYNAMIC_CAST(AP4_MpegAudioSampleDescription, sample_description); + if (audio_desc == NULL) return AP4_ERROR_NOT_SUPPORTED; + if (audio_desc->GetMpeg4AudioObjectType() != AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LC) return AP4_ERROR_NOT_SUPPORTED; + + unsigned int sampling_frequency_index = GetSamplingFrequencyIndex(audio_desc->GetSampleRate()); + unsigned int channel_configuration = audio_desc->GetChannelCount(); + + AP4_DataBuffer data; + if (AP4_SUCCEEDED(sample.ReadData(data))) { + unsigned char* buffer = new unsigned char[7+sample.GetSize()]; + MakeAdtsHeader(buffer, sample.GetSize(), sampling_frequency_index, channel_configuration); + AP4_CopyMemory(buffer+7, data.GetData(), data.GetDataSize()); + AP4_UI64 ts = AP4_ConvertTime(sample.GetDts(), m_TimeScale, 90000); + WritePES(buffer, 7+sample.GetSize(), ts, false, ts, with_pcr, output); + delete[] buffer; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsVideoSampleStream ++---------------------------------------------------------------------*/ +class AP4_Mpeg2TsVideoSampleStream : public AP4_Mpeg2TsWriter::SampleStream +{ +public: + static AP4_Result Create(AP4_UI16 pid, + AP4_UI32 timescale, + AP4_Mpeg2TsWriter::SampleStream*& stream); + AP4_Result WriteSample(AP4_Sample& sample, + AP4_SampleDescription* sample_description, + bool with_pcr, + AP4_ByteStream& output); + +private: + AP4_Mpeg2TsVideoSampleStream(AP4_UI16 pid, AP4_UI32 timescale) : + AP4_Mpeg2TsWriter::SampleStream(pid, + AP4_MPEG2_TS_DEFAULT_STREAM_ID_VIDEO, + AP4_MPEG2_STREAM_TYPE_AVC, + timescale), + m_SampleDescriptionIndex(-1), + m_NaluLengthSize(0) {} + + int m_SampleDescriptionIndex; + AP4_DataBuffer m_Prefix; + unsigned int m_NaluLengthSize; +}; + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsVideoSampleStream::AP4_Mpeg2TsVideoSampleStream ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsVideoSampleStream::Create(AP4_UI16 pid, + AP4_UI32 timescale, + AP4_Mpeg2TsWriter::SampleStream*& stream) +{ + // create the stream object + stream = new AP4_Mpeg2TsVideoSampleStream(pid, timescale); + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsVideoSampleStream::WriteSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsVideoSampleStream::WriteSample(AP4_Sample& sample, + AP4_SampleDescription* sample_description, + bool with_pcr, + AP4_ByteStream& output) +{ + // check the sample description + AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, sample_description); + if (avc_desc == NULL) return AP4_ERROR_NOT_SUPPORTED; + + if ((int)sample.GetDescriptionIndex() != m_SampleDescriptionIndex) { + m_SampleDescriptionIndex = sample.GetDescriptionIndex(); + + // make the SPS/PPS prefix + m_NaluLengthSize = avc_desc->GetNaluLengthSize(); + m_Prefix.SetDataSize(0); + for (unsigned int i=0; i<avc_desc->GetSequenceParameters().ItemCount(); i++) { + AP4_DataBuffer& buffer = avc_desc->GetSequenceParameters()[i]; + unsigned int prefix_size = m_Prefix.GetDataSize(); + m_Prefix.SetDataSize(prefix_size+4+buffer.GetDataSize()); + unsigned char* p = m_Prefix.UseData()+prefix_size; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 1; + AP4_CopyMemory(p, buffer.GetData(), buffer.GetDataSize()); + } + for (unsigned int i=0; i<avc_desc->GetPictureParameters().ItemCount(); i++) { + AP4_DataBuffer& buffer = avc_desc->GetPictureParameters()[i]; + unsigned int prefix_size = m_Prefix.GetDataSize(); + m_Prefix.SetDataSize(prefix_size+4+buffer.GetDataSize()); + unsigned char* p = m_Prefix.UseData()+prefix_size; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 1; + AP4_CopyMemory(p, buffer.GetData(), buffer.GetDataSize()); + } + } + + // read the sample data + AP4_DataBuffer sample_data; + AP4_CHECK(sample.ReadData(sample_data)); + + // allocate a buffer for the PES packet + AP4_DataBuffer pes_data; + pes_data.SetDataSize(6+m_Prefix.GetDataSize()); + unsigned char* pes_buffer = pes_data.UseData(); + + // start of access unit + pes_buffer[0] = 0; + pes_buffer[1] = 0; + pes_buffer[2] = 0; + pes_buffer[3] = 1; + pes_buffer[4] = 9; // NAL type = Access Unit Delimiter; + pes_buffer[5] = 0xE0; // Slice types = ANY + + // copy the prefix + AP4_CopyMemory(pes_buffer+6, m_Prefix.GetData(), m_Prefix.GetDataSize()); + + // write the NAL units + const unsigned char* data = sample_data.GetData(); + unsigned int data_size = sample_data.GetDataSize(); + + while (data_size) { + // sanity check + if (data_size < m_NaluLengthSize) break; + + // get the next NAL unit + AP4_UI32 nalu_size; + if (m_NaluLengthSize == 1) { + nalu_size = *data++; + data_size--; + } else if (m_NaluLengthSize == 2) { + nalu_size = AP4_BytesToInt16BE(data); + data += 2; + data_size -= 2; + } else if (m_NaluLengthSize == 4) { + nalu_size = AP4_BytesToInt32BE(data); + data += 4; + data_size -= 4; + } else { + break; + } + if (nalu_size > data_size) break; + + // add a start code before the NAL unit + unsigned int offset = pes_data.GetDataSize(); + pes_data.SetDataSize(offset+3+nalu_size); + pes_buffer = pes_data.UseData()+offset; + pes_buffer[0] = 0; + pes_buffer[1] = 0; + pes_buffer[2] = 1; + AP4_CopyMemory(pes_buffer+3, data, nalu_size); + + // move to the next NAL unit + data += nalu_size; + data_size -= nalu_size; + } + + // compute the timestamp + AP4_UI64 dts = AP4_ConvertTime(sample.GetDts(), m_TimeScale, 90000); + AP4_UI64 pts = AP4_ConvertTime(sample.GetCts(), m_TimeScale, 90000); + + // write the packet + return WritePES(pes_data.GetData(), pes_data.GetDataSize(), dts, true, pts, with_pcr, output); +} + + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::AP4_Mpeg2TsWriter ++---------------------------------------------------------------------*/ +AP4_Mpeg2TsWriter::AP4_Mpeg2TsWriter() : + m_Audio(NULL), + m_Video(NULL) +{ + m_PAT = new Stream(0); + m_PMT = new Stream(AP4_MPEG2_TS_DEFAULT_PID_PMT); +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::~AP4_Mpeg2TsWriter ++---------------------------------------------------------------------*/ +AP4_Mpeg2TsWriter::~AP4_Mpeg2TsWriter() +{ + delete m_PAT; + delete m_PMT; + delete m_Audio; + delete m_Video; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::WritePAT ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsWriter::WritePAT(AP4_ByteStream& output) +{ + unsigned int payload_size = AP4_MPEG2TS_PACKET_PAYLOAD_SIZE; + m_PAT->WritePacketHeader(true, payload_size, false, 0, output); + + AP4_BitWriter writer(1024); + + writer.Write(0, 8); // pointer + writer.Write(0, 8); // table_id + writer.Write(1, 1); // section_syntax_indicator + writer.Write(0, 1); // '0' + writer.Write(3, 2); // reserved + writer.Write(13, 12);// section_length + writer.Write(1, 16); // transport_stream_id + writer.Write(3, 2); // reserved + writer.Write(0, 5); // version_number + writer.Write(1, 1); // current_next_indicator + writer.Write(0, 8); // section_number + writer.Write(0, 8); // last_section_number + writer.Write(1, 16); // program number + writer.Write(7, 3); // reserved + writer.Write(m_PMT->GetPID(), 13); // program_map_PID + writer.Write(ComputeCRC(writer.GetData()+1, 17-1-4), 32); + + output.Write(writer.GetData(), 17); + + output.Write(StuffingBytes, AP4_MPEG2TS_PACKET_PAYLOAD_SIZE-17); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::WritePMT ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsWriter::WritePMT(AP4_ByteStream& output) +{ + // check that we have at least one media stream + if (m_Audio == NULL && m_Video == NULL) { + return AP4_ERROR_INVALID_STATE; + } + + unsigned int payload_size = AP4_MPEG2TS_PACKET_PAYLOAD_SIZE; + m_PMT->WritePacketHeader(true, payload_size, false, 0, output); + + AP4_BitWriter writer(1024); + + unsigned int section_length = 13; + unsigned int pcr_pid = 0; + if (m_Audio) { + section_length += 5; + pcr_pid = m_Audio->GetPID(); + } + if (m_Video) { + section_length += 5; + pcr_pid = m_Video->GetPID(); + } + + writer.Write(0, 8); // pointer + writer.Write(2, 8); // table_id + writer.Write(1, 1); // section_syntax_indicator + writer.Write(0, 1); // '0' + writer.Write(3, 2); // reserved + writer.Write(section_length, 12); // section_length + writer.Write(1, 16); // program_number + writer.Write(3, 2); // reserved + writer.Write(0, 5); // version_number + writer.Write(1, 1); // current_next_indicator + writer.Write(0, 8); // section_number + writer.Write(0, 8); // last_section_number + writer.Write(7, 3); // reserved + writer.Write(pcr_pid, 13); // PCD_PID + writer.Write(0xF, 4); // reserved + writer.Write(0, 12); // program_info_length + + if (m_Audio) { + writer.Write(m_Audio->m_StreamType, 8); // stream_type + writer.Write(0x7, 3); // reserved + writer.Write(m_Audio->GetPID(), 13); // elementary_PID + writer.Write(0xF, 4); // reserved + writer.Write(0, 12); // ES_info_length + } + + if (m_Video) { + writer.Write(m_Video->m_StreamType, 8); // stream_type + writer.Write(0x7, 3); // reserved + writer.Write(m_Video->GetPID(), 13); // elementary_PID + writer.Write(0xF, 4); // reserved + writer.Write(0, 12); // ES_info_length + } + + writer.Write(ComputeCRC(writer.GetData()+1, section_length-1), 32); // CRC + + output.Write(writer.GetData(), section_length+4); + output.Write(StuffingBytes, AP4_MPEG2TS_PACKET_PAYLOAD_SIZE-(section_length+4)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::SetAudioStream ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsWriter::SetAudioStream(AP4_UI32 timescale, SampleStream*& stream) +{ + // default + stream = NULL; + + AP4_Result result = AP4_Mpeg2TsAudioSampleStream::Create(AP4_MPEG2_TS_DEFAULT_PID_AUDIO, + timescale, + m_Audio); + if (AP4_FAILED(result)) return result; + stream = m_Audio; + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter::SetVideoStream ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Mpeg2TsWriter::SetVideoStream(AP4_UI32 timescale, SampleStream*& stream) +{ + // default + stream = NULL; + + AP4_Result result = AP4_Mpeg2TsVideoSampleStream::Create(AP4_MPEG2_TS_DEFAULT_PID_VIDEO, + timescale, + m_Video); + if (AP4_FAILED(result)) return result; + stream = m_Video; + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Mpeg2Ts.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Mpeg2Ts.h new file mode 100644 index 000000000..0f898b952 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Mpeg2Ts.h @@ -0,0 +1,130 @@ +/***************************************************************** +| +| AP4 - MPEG2 Transport Streams +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_MPEG2_TS_H_ +#define _AP4_MPEG2_TS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| classes ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_Sample; +class AP4_SampleDescription; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI16 AP4_MPEG2_TS_DEFAULT_PID_PMT = 0x100; +const AP4_UI16 AP4_MPEG2_TS_DEFAULT_PID_AUDIO = 0x101; +const AP4_UI16 AP4_MPEG2_TS_DEFAULT_PID_VIDEO = 0x102; +const AP4_UI16 AP4_MPEG2_TS_DEFAULT_STREAM_ID_AUDIO = 0xc0; +const AP4_UI16 AP4_MPEG2_TS_DEFAULT_STREAM_ID_VIDEO = 0xe0; + +const AP4_UI08 AP4_MPEG2_STREAM_TYPE_ISO_IEC_13818_7 = 0x0F; +const AP4_UI08 AP4_MPEG2_STREAM_TYPE_AVC = 0x1B; + +/*---------------------------------------------------------------------- +| AP4_Mpeg2TsWriter ++---------------------------------------------------------------------*/ +/** + * This class is a simple implementation of a converter that can + * convert MP4 audio and video access units into an MPEG2 transport + * stream. + * It currently only supports one audio tracks with MPEG4 AAC LC, and one + * video track with MPEG4 AVC. + */ +class AP4_Mpeg2TsWriter +{ +public: + // classes + class Stream { + public: + Stream(AP4_UI16 pid) : m_PID(pid), m_ContinuityCounter(0) {} + virtual ~Stream() {} + + AP4_UI16 GetPID() { return m_PID; } + void WritePacketHeader(bool payload_start, + unsigned int& payload_size, + bool with_pcr, + AP4_UI64 pcr, + AP4_ByteStream& output); + + private: + unsigned int m_PID; + unsigned int m_ContinuityCounter; + }; + + class SampleStream : public Stream { + public: + SampleStream(AP4_UI16 pid, AP4_UI16 stream_id, AP4_UI08 stream_type, AP4_UI32 timescale) : + Stream(pid), + m_StreamId(stream_id), + m_StreamType(stream_type), + m_TimeScale(timescale) {} + + virtual AP4_Result WritePES(const unsigned char* data, + unsigned int data_size, + AP4_UI64 dts, + bool with_dts, + AP4_UI64 pts, + bool with_pcr, + AP4_ByteStream& output); + virtual AP4_Result WriteSample(AP4_Sample& sample, + AP4_SampleDescription* sample_description, + bool with_pcr, + AP4_ByteStream& output) = 0; + + unsigned int m_StreamId; + AP4_UI08 m_StreamType; + AP4_UI32 m_TimeScale; + }; + + // constructor + AP4_Mpeg2TsWriter(); + ~AP4_Mpeg2TsWriter(); + + Stream* GetPAT() { return m_PAT; } + Stream* GetPMT() { return m_PMT; } + AP4_Result WritePAT(AP4_ByteStream& output); + AP4_Result WritePMT(AP4_ByteStream& output); + AP4_Result SetAudioStream(AP4_UI32 timescale, SampleStream*& stream); + AP4_Result SetVideoStream(AP4_UI32 timescale, SampleStream*& stream); + +private: + Stream* m_PAT; + Stream* m_PMT; + SampleStream* m_Audio; + SampleStream* m_Video; +}; + +#endif // _AP4_MPEG2_TS_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MvhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MvhdAtom.cpp new file mode 100644 index 000000000..3a4e3059a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MvhdAtom.cpp @@ -0,0 +1,202 @@ +/***************************************************************** +| +| AP4 - mvhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4MvhdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MvhdAtom) + +/*---------------------------------------------------------------------- +| AP4_MvhdAtom::Create ++---------------------------------------------------------------------*/ +AP4_MvhdAtom* +AP4_MvhdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version > 1) return NULL; + return new AP4_MvhdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_MvhdAtom::AP4_MvhdAtom ++---------------------------------------------------------------------*/ +AP4_MvhdAtom::AP4_MvhdAtom(AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI32 time_scale, + AP4_UI32 duration, + AP4_UI32 rate, + AP4_UI16 volume) : + AP4_Atom(AP4_ATOM_TYPE_MVHD, AP4_FULL_ATOM_HEADER_SIZE+96, 0, 0), + m_CreationTime(creation_time), + m_ModificationTime(modification_time), + m_TimeScale(time_scale), + m_Duration(duration), + m_Rate(rate), + m_Volume(volume), + m_NextTrackId(0xFFFFFFFF) +{ + m_Matrix[0] = 0x00010000; + m_Matrix[1] = 0; + m_Matrix[2] = 0; + m_Matrix[3] = 0; + m_Matrix[4] = 0x00010000; + m_Matrix[5] = 0; + m_Matrix[6] = 0; + m_Matrix[7] = 0; + m_Matrix[8] = 0x40000000; + + AP4_SetMemory(m_Reserved1, 0, sizeof(m_Reserved1)); + AP4_SetMemory(m_Reserved2, 0, sizeof(m_Reserved2)); + AP4_SetMemory(m_Predefined, 0, sizeof(m_Predefined)); +} + +/*---------------------------------------------------------------------- +| AP4_MvhdAtom::AP4_MvhdAtom ++---------------------------------------------------------------------*/ +AP4_MvhdAtom::AP4_MvhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_MVHD, size, version, flags) +{ + if (m_Version == 0) { + AP4_UI32 creation_time; + stream.ReadUI32(creation_time); + m_CreationTime = creation_time; + AP4_UI32 modification_time; + stream.ReadUI32(modification_time); + m_ModificationTime = modification_time; + stream.ReadUI32(m_TimeScale); + AP4_UI32 duration; + stream.ReadUI32(duration); + m_Duration = duration; + } else { + stream.ReadUI64(m_CreationTime); + stream.ReadUI64(m_ModificationTime); + stream.ReadUI32(m_TimeScale); + stream.ReadUI64(m_Duration); + } + + stream.ReadUI32(m_Rate); + stream.ReadUI16(m_Volume); + stream.Read(m_Reserved1, sizeof(m_Reserved1)); + stream.Read(m_Reserved2, sizeof(m_Reserved2)); + for (int i=0; i<9; i++) { + stream.ReadUI32(m_Matrix[i]); + } + stream.Read(m_Predefined, sizeof(m_Predefined)); + stream.ReadUI32(m_NextTrackId); +} + +/*---------------------------------------------------------------------- +| AP4_MvhdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MvhdAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + if (m_Version == 0) { + result = stream.WriteUI32((AP4_UI32)m_CreationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_ModificationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_TimeScale); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_Duration); + } else { + result = stream.WriteUI64(m_CreationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_ModificationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_TimeScale); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_Duration); + if (AP4_FAILED(result)) return result; + } + + // rate & volume + result = stream.WriteUI32(m_Rate); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI16(m_Volume); + if (AP4_FAILED(result)) return result; + + // reserved + result = stream.Write(m_Reserved1, sizeof(m_Reserved1)); + if (AP4_FAILED(result)) return result; + result = stream.Write(m_Reserved2, sizeof(m_Reserved2)); + if (AP4_FAILED(result)) return result; + + // matrix + for (int i=0; i<9; i++) { + result = stream.WriteUI32(m_Matrix[i]); + if (AP4_FAILED(result)) return result; + } + + // pre-defined + result = stream.Write(m_Predefined, sizeof(m_Predefined)); + if (AP4_FAILED(result)) return result; + + // next track id + return stream.WriteUI32(m_NextTrackId); +} + +/*---------------------------------------------------------------------- +| AP4_MvhdAtom::GetDurationMs ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_MvhdAtom::GetDurationMs() +{ + if (m_TimeScale) { + return (AP4_UI32)AP4_ConvertTime(m_Duration, m_TimeScale, 1000); + } else { + return 0; + } +} + +/*---------------------------------------------------------------------- +| AP4_MvhdAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_MvhdAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("timescale", m_TimeScale); + inspector.AddField("duration", m_Duration); + inspector.AddField("duration(ms)", GetDurationMs()); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MvhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MvhdAtom.h new file mode 100644 index 000000000..b3d4de11d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4MvhdAtom.h @@ -0,0 +1,88 @@ +/***************************************************************** +| +| AP4 - mvhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_MVHD_ATOM_H_ +#define _AP4_MVHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4List.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_MvhdAtom ++---------------------------------------------------------------------*/ +class AP4_MvhdAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_MvhdAtom, AP4_Atom) + + // class methods + static AP4_MvhdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_MvhdAtom(AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI32 time_scale, + AP4_UI32 duration, + AP4_UI32 rate, + AP4_UI16 volume); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + AP4_UI64 GetDuration() { return m_Duration; } + void SetDuration(AP4_UI64 duration) { m_Duration = duration;} + AP4_UI32 GetDurationMs(); + AP4_UI32 GetTimeScale() { return m_TimeScale; } + AP4_Result SetTimeScale(AP4_UI32 time_scale) { + m_TimeScale = time_scale; + return AP4_SUCCESS; + } + +private: + // methods + AP4_MvhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI64 m_CreationTime; + AP4_UI64 m_ModificationTime; + AP4_UI32 m_TimeScale; + AP4_UI64 m_Duration; + AP4_UI32 m_Rate; + AP4_UI16 m_Volume; + AP4_UI08 m_Reserved1[2]; + AP4_UI08 m_Reserved2[8]; + AP4_UI32 m_Matrix[9]; + AP4_UI08 m_Predefined[24]; + AP4_UI32 m_NextTrackId; +}; + +#endif // _AP4_MVHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4NmhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4NmhdAtom.cpp new file mode 100644 index 000000000..d6a660962 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4NmhdAtom.cpp @@ -0,0 +1,75 @@ +/***************************************************************** +| +| AP4 - nmhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4NmhdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_NmhdAtom::Create ++---------------------------------------------------------------------*/ +AP4_NmhdAtom* +AP4_NmhdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_NmhdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_NmhdAtom::AP4_NmhdAtom ++---------------------------------------------------------------------*/ +AP4_NmhdAtom::AP4_NmhdAtom() : + AP4_Atom(AP4_ATOM_TYPE_NMHD, AP4_FULL_ATOM_HEADER_SIZE, 0, 0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_NmhdAtom::AP4_NmhdAtom ++---------------------------------------------------------------------*/ +AP4_NmhdAtom::AP4_NmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& /* stream */) : + AP4_Atom(AP4_ATOM_TYPE_NMHD, size, version, flags) +{ +} + +/*---------------------------------------------------------------------- +| AP4_NmhdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_NmhdAtom::WriteFields(AP4_ByteStream& /* stream */) +{ + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4NmhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4NmhdAtom.h new file mode 100644 index 000000000..8c2efd336 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4NmhdAtom.h @@ -0,0 +1,58 @@ +/***************************************************************** +| +| AP4 - nmhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_NMHD_ATOM_H_ +#define _AP4_NMHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_NmhdAtom ++---------------------------------------------------------------------*/ +class AP4_NmhdAtom : public AP4_Atom +{ +public: + // class methods + static AP4_NmhdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_NmhdAtom(); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_NmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); +}; + +#endif // _AP4_NMHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ObjectDescriptor.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ObjectDescriptor.cpp new file mode 100644 index 000000000..1b74261d9 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ObjectDescriptor.cpp @@ -0,0 +1,430 @@ +/***************************************************************** +| +| AP4 - Object Descriptor +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4ObjectDescriptor.h" +#include "Ap4DescriptorFactory.h" +#include "Ap4Utils.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_ObjectDescriptor) +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DescriptorUpdateCommand) + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::AP4_ObjectDescriptor ++---------------------------------------------------------------------*/ +AP4_ObjectDescriptor::AP4_ObjectDescriptor(AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(tag, header_size, payload_size), + m_UrlFlag(false) +{ +} + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::AP4_ObjectDescriptor ++---------------------------------------------------------------------*/ +AP4_ObjectDescriptor::AP4_ObjectDescriptor(AP4_UI08 tag, AP4_UI16 id) : + AP4_Descriptor(tag, 3, 2), + m_ObjectDescriptorId(id), + m_UrlFlag(false) +{ +} + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::AP4_ObjectDescriptor ++---------------------------------------------------------------------*/ +AP4_ObjectDescriptor::AP4_ObjectDescriptor(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Descriptor(tag, header_size, payload_size) +{ + AP4_Position start; + stream.Tell(start); + + // read descriptor fields + unsigned short bits; + stream.ReadUI16(bits); + m_ObjectDescriptorId = (bits>>6); + m_UrlFlag = ((bits&(1<<5))!=0); + + if (m_UrlFlag) { + unsigned char url_length; + stream.ReadUI08(url_length); + char url[256]; + stream.Read(url, url_length); + url[url_length] = '\0'; + m_Url = url; + } + + // read other descriptors + AP4_Position offset; + stream.Tell(offset); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, + payload_size-AP4_Size(offset-start)); + AP4_Descriptor* descriptor = NULL; + while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, + descriptor) + == AP4_SUCCESS) { + m_SubDescriptors.Add(descriptor); + } + substream->Release(); +} + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::~AP4_ObjectDescriptor ++---------------------------------------------------------------------*/ +AP4_ObjectDescriptor::~AP4_ObjectDescriptor() +{ + m_SubDescriptors.DeleteReferences(); +} + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::FindSubDescriptor ++---------------------------------------------------------------------*/ +AP4_Descriptor* +AP4_ObjectDescriptor::FindSubDescriptor(AP4_UI08 tag) const +{ + AP4_Descriptor* descriptor = NULL; + AP4_Result result = m_SubDescriptors.Find(AP4_DescriptorFinder(tag), descriptor); + if (AP4_FAILED(result)) return NULL; + + return descriptor; +} + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ObjectDescriptor::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // id and flag + unsigned short bits = (m_ObjectDescriptorId<<6)|(m_UrlFlag?(1<<5):0)|0x1F; + result = stream.WriteUI16(bits); + if (AP4_FAILED(result)) return result; + + // optional url + if (m_UrlFlag) { + stream.WriteUI08((AP4_UI08)m_Url.GetLength()); + stream.Write(m_Url.GetChars(), m_Url.GetLength()); + } + + // write the sub descriptors + m_SubDescriptors.Apply(AP4_DescriptorListWriter(stream)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ObjectDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + inspector.StartElement("[ObjectDescriptor]", info); + inspector.AddField("id", m_ObjectDescriptorId); + if (m_UrlFlag) { + inspector.AddField("url", m_Url.GetChars()); + } + + // inspect children + m_SubDescriptors.Apply(AP4_DescriptorListInspector(inspector)); + + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor::AddSubDescriptor ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ObjectDescriptor::AddSubDescriptor(AP4_Descriptor* descriptor) +{ + m_SubDescriptors.Add(descriptor); + m_PayloadSize += descriptor->GetSize(); + + // check that the header is still large enough to encode the payload + // length + unsigned int min_header_size = MinHeaderSize(m_PayloadSize); + if (min_header_size > m_HeaderSize) m_HeaderSize = min_header_size; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_InitialObjectDescriptor::AP4_InitialObjectDescriptor ++---------------------------------------------------------------------*/ +AP4_InitialObjectDescriptor::AP4_InitialObjectDescriptor( + AP4_UI08 tag, // should be AP4_DESCRIPTOR_TAG_IOD or AP4_DESCRIPTOR_TAG_MP4_IOD + AP4_UI16 object_descriptor_id, + bool include_inline_profile_level, + AP4_UI08 od_profile_level_indication, + AP4_UI08 scene_profile_level_indication, + AP4_UI08 audio_profile_level_indication, + AP4_UI08 visual_profile_level_indication, + AP4_UI08 graphics_profile_level_indication) : + AP4_ObjectDescriptor(tag, object_descriptor_id), + m_IncludeInlineProfileLevelFlag(include_inline_profile_level), + m_OdProfileLevelIndication(od_profile_level_indication), + m_SceneProfileLevelIndication(scene_profile_level_indication), + m_AudioProfileLevelIndication(audio_profile_level_indication), + m_VisualProfileLevelIndication(visual_profile_level_indication), + m_GraphicsProfileLevelIndication(graphics_profile_level_indication) +{ + m_PayloadSize = 7; +} + +/*---------------------------------------------------------------------- +| AP4_InitialObjectDescriptor::AP4_InitialObjectDescriptor ++---------------------------------------------------------------------*/ +AP4_InitialObjectDescriptor::AP4_InitialObjectDescriptor(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_ObjectDescriptor(tag, header_size, payload_size), + m_OdProfileLevelIndication(0), + m_SceneProfileLevelIndication(0), + m_AudioProfileLevelIndication(0), + m_VisualProfileLevelIndication(0), + m_GraphicsProfileLevelIndication(0) +{ + AP4_Position start; + stream.Tell(start); + + // read descriptor fields + unsigned short bits; + stream.ReadUI16(bits); + m_ObjectDescriptorId = (bits>>6); + m_UrlFlag = ((bits&(1<<5))!=0); + m_IncludeInlineProfileLevelFlag = ((bits&(1<<4))!=0); + + if (m_UrlFlag) { + unsigned char url_length; + stream.ReadUI08(url_length); + char url[256]; + stream.Read(url, url_length); + url[url_length] = '\0'; + m_Url = url; + } else { + stream.ReadUI08(m_OdProfileLevelIndication); + stream.ReadUI08(m_SceneProfileLevelIndication); + stream.ReadUI08(m_AudioProfileLevelIndication); + stream.ReadUI08(m_VisualProfileLevelIndication); + stream.ReadUI08(m_GraphicsProfileLevelIndication); + } + + // read other descriptors + AP4_Position offset; + stream.Tell(offset); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, + payload_size-AP4_Size(offset-start)); + AP4_Descriptor* descriptor = NULL; + while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, + descriptor) + == AP4_SUCCESS) { + m_SubDescriptors.Add(descriptor); + } + substream->Release(); +} + +/*---------------------------------------------------------------------- +| AP4_InitialObjectDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_InitialObjectDescriptor::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // id and flags + unsigned short bits = (m_ObjectDescriptorId<<6) | + (m_UrlFlag?(1<<5):0) | + (m_IncludeInlineProfileLevelFlag?(1<<4):0)| + 0xF; + result = stream.WriteUI16(bits); + if (AP4_FAILED(result)) return result; + + // optional url + if (m_UrlFlag) { + stream.WriteUI08((AP4_UI08)m_Url.GetLength()); + stream.Write(m_Url.GetChars(), m_Url.GetLength()); + } else { + stream.WriteUI08(m_OdProfileLevelIndication); + stream.WriteUI08(m_SceneProfileLevelIndication); + stream.WriteUI08(m_AudioProfileLevelIndication); + stream.WriteUI08(m_VisualProfileLevelIndication); + stream.WriteUI08(m_GraphicsProfileLevelIndication); + } + + // write the sub descriptors + m_SubDescriptors.Apply(AP4_DescriptorListWriter(stream)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_InitialObjectDescriptor::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_InitialObjectDescriptor::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + inspector.StartElement("[InitialObjectDescriptor]", info); + inspector.AddField("id", m_ObjectDescriptorId); + if (m_UrlFlag) { + inspector.AddField("url", m_Url.GetChars()); + } else { + inspector.AddField("include inline profile level flag", + m_IncludeInlineProfileLevelFlag, + AP4_AtomInspector::HINT_BOOLEAN); + inspector.AddField("OD profile level", m_OdProfileLevelIndication, AP4_AtomInspector::HINT_HEX); + inspector.AddField("scene profile level", m_SceneProfileLevelIndication, AP4_AtomInspector::HINT_HEX); + inspector.AddField("audio profile level", m_AudioProfileLevelIndication, AP4_AtomInspector::HINT_HEX); + inspector.AddField("visual profile level", m_VisualProfileLevelIndication, AP4_AtomInspector::HINT_HEX); + inspector.AddField("graphics profile level", m_GraphicsProfileLevelIndication, AP4_AtomInspector::HINT_HEX); + } + + // inspect children + m_SubDescriptors.Apply(AP4_DescriptorListInspector(inspector)); + + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_DescriptorUpdateCommand::AP4_DescriptorUpdateCommand ++---------------------------------------------------------------------*/ +AP4_DescriptorUpdateCommand::AP4_DescriptorUpdateCommand(AP4_UI08 tag) : + AP4_Command(tag, 2, 0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_DescriptorUpdateCommand::AP4_DescriptorUpdateCommand ++---------------------------------------------------------------------*/ +AP4_DescriptorUpdateCommand::AP4_DescriptorUpdateCommand( + AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size) : + AP4_Command(tag, header_size, payload_size) +{ + // read the descriptors + AP4_Position offset; + stream.Tell(offset); + AP4_SubStream* substream = new AP4_SubStream(stream, offset, + payload_size); + AP4_Descriptor* descriptor = NULL; + while (AP4_DescriptorFactory::CreateDescriptorFromStream(*substream, descriptor) == AP4_SUCCESS) { + m_Descriptors.Add(descriptor); + } + substream->Release(); +} + +/*---------------------------------------------------------------------- +| AP4_DescriptorUpdateCommand::~AP4_DescriptorUpdateCommand ++---------------------------------------------------------------------*/ +AP4_DescriptorUpdateCommand::~AP4_DescriptorUpdateCommand() +{ + m_Descriptors.DeleteReferences(); +} + +/*---------------------------------------------------------------------- +| AP4_DescriptorUpdateCommand::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DescriptorUpdateCommand::WriteFields(AP4_ByteStream& stream) +{ + // write the descriptors + m_Descriptors.Apply(AP4_DescriptorListWriter(stream)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_DescriptorUpdateCommand::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DescriptorUpdateCommand::Inspect(AP4_AtomInspector& inspector) +{ + char info[64]; + AP4_FormatString(info, sizeof(info), "size=%ld+%ld", + GetHeaderSize(),m_PayloadSize); + switch (GetTag()) { + case AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_UPDATE: + inspector.StartElement("[ObjectDescriptorUpdate]", info); + break; + + case AP4_COMMAND_TAG_IPMP_DESCRIPTOR_UPDATE: + inspector.StartElement("[IPMP_DescriptorUpdate]", info); + break; + + default: + inspector.StartElement("[DescriptorUpdate]", info); + break; + } + + // inspect children + m_Descriptors.Apply(AP4_DescriptorListInspector(inspector)); + + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_DescriptorUpdateCommand::AddDescriptor ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DescriptorUpdateCommand::AddDescriptor(AP4_Descriptor* descriptor) +{ + m_Descriptors.Add(descriptor); + m_PayloadSize += descriptor->GetSize(); + + // check that the header is still large enough to encode the payload + // length + unsigned int min_header_size = MinHeaderSize(m_PayloadSize); + if (min_header_size > m_HeaderSize) m_HeaderSize = min_header_size; + + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ObjectDescriptor.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ObjectDescriptor.h new file mode 100644 index 000000000..8b29c609c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4ObjectDescriptor.h @@ -0,0 +1,167 @@ +/***************************************************************** +| +| AP4 - Object Descriptor +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_OBJECT_DESCRIPTOR_H_ +#define _AP4_OBJECT_DESCRIPTOR_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4List.h" +#include "Ap4String.h" +#include "Ap4Descriptor.h" +#include "Ap4Command.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_DESCRIPTOR_TAG_OD = 0x01; +const AP4_UI08 AP4_DESCRIPTOR_TAG_IOD = 0x02; +const AP4_UI08 AP4_DESCRIPTOR_TAG_MP4_OD = 0x11; +const AP4_UI08 AP4_DESCRIPTOR_TAG_MP4_IOD = 0x10; + +/*---------------------------------------------------------------------- +| AP4_ObjectDescriptor ++---------------------------------------------------------------------*/ +class AP4_ObjectDescriptor : public AP4_Descriptor +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_ObjectDescriptor, AP4_Descriptor) + + // methods + AP4_ObjectDescriptor(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size); + AP4_ObjectDescriptor(AP4_UI08 tag, AP4_UI16 id); + virtual ~AP4_ObjectDescriptor(); + + /** + * Add a sub-descriptor. + * Ownership of the sub-descriptor object is transfered. + */ + virtual AP4_Result AddSubDescriptor(AP4_Descriptor* descriptor); + + virtual AP4_Descriptor* FindSubDescriptor(AP4_UI08 tag) const; + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + AP4_UI16 GetObjectDescriptorId() const { return m_ObjectDescriptorId; } + bool GetUrlFlag() const { return m_UrlFlag; } + const AP4_String& GetUrl() const { return m_Url;} + + protected: + // constructor + AP4_ObjectDescriptor(AP4_UI08 tag, AP4_Size header_size, AP4_Size payload_size); + + // members + AP4_UI16 m_ObjectDescriptorId; + bool m_UrlFlag; + AP4_String m_Url; + mutable AP4_List<AP4_Descriptor> m_SubDescriptors; +}; + +/*---------------------------------------------------------------------- +| AP4_InitialObjectDescriptor ++---------------------------------------------------------------------*/ +class AP4_InitialObjectDescriptor : public AP4_ObjectDescriptor +{ + public: + // methods + AP4_InitialObjectDescriptor(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size); + AP4_InitialObjectDescriptor(AP4_UI08 tag, // should be AP4_DESCRIPTOR_TAG_IOD or AP4_DESCRIPTOR_TAG_MP4_IOD + AP4_UI16 object_descriptor_id, + bool include_inline_profile_level, + AP4_UI08 od_profile_level_indication, + AP4_UI08 scene_profile_level_indication, + AP4_UI08 audio_profile_level_indication, + AP4_UI08 visual_profile_level_indication, + AP4_UI08 graphics_profile_level_indication); + + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + bool GetIncludeProfileLevelFlag() const { return m_IncludeInlineProfileLevelFlag; } + AP4_UI08 GetOdProfileLevelIndication() const { return m_OdProfileLevelIndication; } + AP4_UI08 GetSceneProfileLevelIndication() const { return m_SceneProfileLevelIndication; } + AP4_UI08 GetAudioProfileLevelIndication() const { return m_AudioProfileLevelIndication; } + AP4_UI08 GetVisualProfileLevelIndication() const { return m_VisualProfileLevelIndication; } + AP4_UI08 GetGraphicsProfileLevelIndication() const { return m_GraphicsProfileLevelIndication; } + + private: + // members + bool m_IncludeInlineProfileLevelFlag; + AP4_UI08 m_OdProfileLevelIndication; + AP4_UI08 m_SceneProfileLevelIndication; + AP4_UI08 m_AudioProfileLevelIndication; + AP4_UI08 m_VisualProfileLevelIndication; + AP4_UI08 m_GraphicsProfileLevelIndication; +}; + +/*---------------------------------------------------------------------- +| AP4_DescriptorUpdateCommand ++---------------------------------------------------------------------*/ +/** + * This class is used for ObjectDescriptorUpdateCommand and + * IPMP_DescriptorUpdateCommand + */ +class AP4_DescriptorUpdateCommand : public AP4_Command +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DescriptorUpdateCommand, AP4_Command) + + // methods + AP4_DescriptorUpdateCommand(AP4_UI08 tag); + AP4_DescriptorUpdateCommand(AP4_ByteStream& stream, + AP4_UI08 tag, + AP4_Size header_size, + AP4_Size payload_size); + virtual ~AP4_DescriptorUpdateCommand(); + virtual AP4_Result AddDescriptor(AP4_Descriptor* descriptor); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + + // accessors + const AP4_List<AP4_Descriptor>& GetDescriptors() { return m_Descriptors; } + + protected: + // members + mutable AP4_List<AP4_Descriptor> m_Descriptors; +}; + +#endif // _AP4_OBJECT_DESCRIPTOR_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdafAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdafAtom.cpp new file mode 100644 index 000000000..28805ecef --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdafAtom.cpp @@ -0,0 +1,116 @@ +/***************************************************************** +| +| AP4 - odaf Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4OdafAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_OdafAtom) + +/*---------------------------------------------------------------------- +| AP4_OdafAtom::Create ++---------------------------------------------------------------------*/ +AP4_OdafAtom* +AP4_OdafAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_OdafAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_OdafAtom::AP4_OdafAtom ++---------------------------------------------------------------------*/ +AP4_OdafAtom::AP4_OdafAtom(bool selective_encryption, + AP4_UI08 key_length_indicator, + AP4_UI08 iv_length) : + AP4_Atom(AP4_ATOM_TYPE_ODAF, AP4_FULL_ATOM_HEADER_SIZE+3, 0, 0), + m_SelectiveEncryption(selective_encryption), + m_KeyIndicatorLength(key_length_indicator), + m_IvLength(iv_length) +{ +} + +/*---------------------------------------------------------------------- +| AP4_OdafAtom::AP4_OdafAtom ++---------------------------------------------------------------------*/ +AP4_OdafAtom::AP4_OdafAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_ODAF, size, version, flags) +{ + AP4_UI08 s; + stream.ReadUI08(s); + m_SelectiveEncryption = ((s&0x80) != 0); + stream.ReadUI08(m_KeyIndicatorLength); + stream.ReadUI08(m_IvLength); +} + +/*---------------------------------------------------------------------- +| AP4_OdafAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OdafAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // selective encryption + result = stream.WriteUI08(m_SelectiveEncryption ? 0x80 : 0); + if (AP4_FAILED(result)) return result; + + // key indicator length + result = stream.WriteUI08(m_KeyIndicatorLength); + if (AP4_FAILED(result)) return result; + + // IV length + result = stream.WriteUI08(m_IvLength); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_OdafAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OdafAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("selective_encryption", m_SelectiveEncryption); + inspector.AddField("key_indicator_length", m_KeyIndicatorLength); + inspector.AddField("IV_length", m_IvLength); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdafAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdafAtom.h new file mode 100644 index 000000000..22ba860ee --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdafAtom.h @@ -0,0 +1,74 @@ +/***************************************************************** +| +| AP4 - odaf Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_ODAF_ATOM_H_ +#define _AP4_ODAF_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_OdafAtom ++---------------------------------------------------------------------*/ +class AP4_OdafAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_OdafAtom, AP4_Atom) + + // class methods + static AP4_OdafAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_OdafAtom(bool m_SelectiveEncryption, + AP4_UI08 m_KeyIndicatorLength, + AP4_UI08 m_IvLength); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + bool GetSelectiveEncryption() { return m_SelectiveEncryption; } + AP4_UI08 GetKeyIndicatorLength() { return m_KeyIndicatorLength; } + AP4_UI08 GetIvLength() { return m_IvLength; } + +private: + // methods + AP4_OdafAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + bool m_SelectiveEncryption; + AP4_UI08 m_KeyIndicatorLength; + AP4_UI08 m_IvLength; +}; + +#endif // _AP4_ODAF_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OddaAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OddaAtom.cpp new file mode 100644 index 000000000..d7a08796a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OddaAtom.cpp @@ -0,0 +1,170 @@ +/***************************************************************** +| +| AP4 - odda Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4OddaAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_OddaAtom) + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::Create ++---------------------------------------------------------------------*/ +AP4_OddaAtom* +AP4_OddaAtom::Create(AP4_UI64 size, + AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_OddaAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::AP4_OddaAtom ++---------------------------------------------------------------------*/ +AP4_OddaAtom::AP4_OddaAtom(AP4_UI64 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_ODDA, size, true, version, flags) +{ + // data length + stream.ReadUI64(m_EncryptedDataLength); + + // get the source stream position + AP4_Position position; + stream.Tell(position); + + // create a substream to represent the payload + m_EncryptedPayload = new AP4_SubStream(stream, position, m_EncryptedDataLength); + + // seek to the end + stream.Seek(position+m_EncryptedDataLength); +} + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::AP4_OddaAtom ++---------------------------------------------------------------------*/ +AP4_OddaAtom::AP4_OddaAtom(AP4_ByteStream& encrypted_payload) : + AP4_Atom(AP4_ATOM_TYPE_ODDA, 0, true, 0, 0) +{ + // encrypted data length + encrypted_payload.GetSize(m_EncryptedDataLength); + + // update our size + SetSize(AP4_FULL_ATOM_HEADER_SIZE_64+8+m_EncryptedDataLength, true); + + // keep a reference to the encrypted payload + m_EncryptedPayload = &encrypted_payload; + m_EncryptedPayload->AddReference(); +} + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::~AP4_OddaAtom ++---------------------------------------------------------------------*/ +AP4_OddaAtom::~AP4_OddaAtom() +{ + if (m_EncryptedPayload) m_EncryptedPayload->Release(); +} + + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::SetEncryptedPayload ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OddaAtom::SetEncryptedPayload(AP4_ByteStream& stream, AP4_LargeSize length) +{ + // keep a reference to the stream + if (m_EncryptedPayload) { + m_EncryptedPayload->Release(); + } + m_EncryptedPayload = &stream; + m_EncryptedPayload->AddReference(); + + // update the size + m_EncryptedDataLength = length; + SetSize(AP4_FULL_ATOM_HEADER_SIZE_64 + 8 + length, true); + if (m_Parent) m_Parent->OnChildChanged(this); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::SetEncryptedPayload ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OddaAtom::SetEncryptedPayload(AP4_ByteStream& stream) +{ + // the new encrypted data length is the size of the stream + AP4_LargeSize length; + AP4_Result result = stream.GetSize(length); + if (AP4_FAILED(result)) return result; + + return SetEncryptedPayload(stream, length); +} + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OddaAtom::WriteFields(AP4_ByteStream& stream) +{ + // write the content type + AP4_CHECK(stream.WriteUI64(m_EncryptedDataLength)); + + // check that we have a source stream + // and a normal size + if (m_EncryptedPayload == NULL || GetSize() < 8) { + return AP4_FAILURE; + } + + // rewind the encrypted stream + AP4_CHECK(m_EncryptedPayload->Seek(0)); + + // copy the encrypted stream to the output + AP4_CHECK(m_EncryptedPayload->CopyTo(stream, m_EncryptedDataLength)); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_OddaAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OddaAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("encrypted_data_length", (AP4_UI32)m_EncryptedDataLength); + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OddaAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OddaAtom.h new file mode 100644 index 000000000..58a402ce5 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OddaAtom.h @@ -0,0 +1,87 @@ +/***************************************************************** +| +| AP4 - odda Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_ODDA_ATOM_H_ +#define _AP4_ODDA_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| AP4_OddaAtom ++---------------------------------------------------------------------*/ +class AP4_OddaAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_OddaAtom, AP4_Atom) + + // class methods + static AP4_OddaAtom* Create(AP4_UI64 size, + AP4_ByteStream& stream); + + // constructor + AP4_OddaAtom(AP4_ByteStream& encrypted_payload); + + // destructor + ~AP4_OddaAtom(); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI64 GetEncryptedDataLength() { return m_EncryptedDataLength; } + + /** + * Sets the encrypted payload stream (and releases any existing stream references) + */ + AP4_Result SetEncryptedPayload(AP4_ByteStream& stream); + AP4_Result SetEncryptedPayload(AP4_ByteStream& stream, AP4_LargeSize length); + + /** + * Returns a reference to the encrypted payload stream (does not increment the reference counter) + */ + AP4_ByteStream& GetEncryptedPayload() { return *m_EncryptedPayload; } + +private: + // methods + AP4_OddaAtom(AP4_UI64 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI64 m_EncryptedDataLength; + AP4_ByteStream* m_EncryptedPayload; +}; + +#endif // _AP4_ODDA_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdheAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdheAtom.cpp new file mode 100644 index 000000000..f4e2bf5c8 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdheAtom.cpp @@ -0,0 +1,130 @@ +/***************************************************************** +| +| AP4 - odhe Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4OdheAtom.h" +#include "Ap4OhdrAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_OdheAtom) + +/*---------------------------------------------------------------------- +| AP4_OdheAtom::Create ++---------------------------------------------------------------------*/ +AP4_OdheAtom* +AP4_OdheAtom::Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_OdheAtom(size, version, flags, stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_OdheAtom::AP4_OdheAtom ++---------------------------------------------------------------------*/ +AP4_OdheAtom::AP4_OdheAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_ContainerAtom(AP4_ATOM_TYPE_ODHE, size, false, version, flags) +{ + // read the content type + AP4_UI08 content_type_length; + stream.ReadUI08(content_type_length); + char content_type[256]; + stream.Read(content_type, content_type_length); + m_ContentType.Assign(content_type, content_type_length); + + // read the children + AP4_Size bytes_available = size-(AP4_FULL_ATOM_HEADER_SIZE+1+content_type_length); + ReadChildren(atom_factory, stream, bytes_available); +} + +/*---------------------------------------------------------------------- +| AP4_OdheAtom::AP4_OdheAtom ++---------------------------------------------------------------------*/ +AP4_OdheAtom::AP4_OdheAtom(const char* content_type, + AP4_OhdrAtom* ohdr) : + AP4_ContainerAtom(AP4_ATOM_TYPE_ODHE, (AP4_UI32)0, (AP4_UI32)0), + m_ContentType(content_type) +{ + m_Size32 += 1+m_ContentType.GetLength(); + AddChild(ohdr); +} + +/*---------------------------------------------------------------------- +| AP4_OdheAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OdheAtom::WriteFields(AP4_ByteStream& stream) +{ + // write the content type + AP4_CHECK(stream.WriteUI08((AP4_UI08)m_ContentType.GetLength())); + if (m_ContentType.GetLength()) { + AP4_CHECK(stream.Write(m_ContentType.GetChars(), m_ContentType.GetLength())); + } + + // write the children + return m_Children.Apply(AP4_AtomListWriter(stream)); +} + +/*---------------------------------------------------------------------- +| AP4_OdheAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OdheAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("content_type", m_ContentType.GetChars()); + return InspectChildren(inspector); +} + +/*---------------------------------------------------------------------- +| AP4_OdheAtom::OnChildChanged ++---------------------------------------------------------------------*/ +void +AP4_OdheAtom::OnChildChanged(AP4_Atom*) +{ + // remcompute our size + AP4_UI64 size = GetHeaderSize()+1+m_ContentType.GetLength(); + m_Children.Apply(AP4_AtomSizeAdder(size)); + SetSize(size); + + // update our parent + if (m_Parent) m_Parent->OnChildChanged(this); +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdheAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdheAtom.h new file mode 100644 index 000000000..44477ae13 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OdheAtom.h @@ -0,0 +1,87 @@ +/***************************************************************** +| +| AP4 - odhe Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_ODHE_ATOM_H_ +#define _AP4_ODHE_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4ContainerAtom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_OhdrAtom; + +/*---------------------------------------------------------------------- +| AP4_OdheAtom ++---------------------------------------------------------------------*/ +class AP4_OdheAtom : public AP4_ContainerAtom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_OdheAtom, AP4_ContainerAtom) + + // class methods + static AP4_OdheAtom* Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // constructor + /** + * @param: ohdr ohdr atom passed with transfer of ownership semantics + */ + AP4_OdheAtom(const char* content_type, AP4_OhdrAtom* ohdr); + + // AP4_Atom methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // AP4_AtomParent methods + virtual void OnChildChanged(AP4_Atom* child); + + // methods + const AP4_String& GetContentType() { return m_ContentType; } + +private: + // methods + AP4_OdheAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // members + AP4_String m_ContentType; + +}; + +#endif // _AP4_ODHE_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OhdrAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OhdrAtom.cpp new file mode 100644 index 000000000..f74e0d8f5 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OhdrAtom.cpp @@ -0,0 +1,214 @@ +/***************************************************************** +| +| AP4 - ohdr Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Utils.h" +#include "Ap4OhdrAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_OhdrAtom) + +/*---------------------------------------------------------------------- +| AP4_OhdrAtom::Create ++---------------------------------------------------------------------*/ +AP4_OhdrAtom* +AP4_OhdrAtom::Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_OhdrAtom(size, version, flags, stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_OhdrAtom::AP4_OhdrAtom ++---------------------------------------------------------------------*/ +AP4_OhdrAtom::AP4_OhdrAtom(AP4_UI08 encryption_method, + AP4_UI08 padding_scheme, + AP4_UI64 plaintext_length, + const char* content_id, + const char* rights_issuer_url, + const AP4_Byte* textual_headers, + AP4_Size textual_headers_size) : + AP4_ContainerAtom(AP4_ATOM_TYPE_OHDR, (AP4_UI32)0, (AP4_UI32)0), + m_EncryptionMethod(encryption_method), + m_PaddingScheme(padding_scheme), + m_PlaintextLength(plaintext_length), + m_ContentId(content_id), + m_RightsIssuerUrl(rights_issuer_url), + m_TextualHeaders(textual_headers, textual_headers_size) +{ + m_Size32 += 1+1+8+2+2+2+m_ContentId.GetLength()+m_RightsIssuerUrl.GetLength()+textual_headers_size; +} + +/*---------------------------------------------------------------------- +| AP4_OhdrAtom::AP4_OhdrAtom ++---------------------------------------------------------------------*/ +AP4_OhdrAtom::AP4_OhdrAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_ContainerAtom(AP4_ATOM_TYPE_OHDR, size, false, version, flags) +{ + // encryption method + stream.ReadUI08(m_EncryptionMethod); + + // padding scheme + stream.ReadUI08(m_PaddingScheme); + + // plaintext length + stream.ReadUI64(m_PlaintextLength); + + // string lengths + AP4_UI16 content_id_length; + AP4_UI16 rights_issuer_url_length; + AP4_UI16 textual_headers_length; + stream.ReadUI16(content_id_length); + stream.ReadUI16(rights_issuer_url_length); + stream.ReadUI16(textual_headers_length); + + // content id + char* buffer = new char[content_id_length]; + stream.Read(buffer, content_id_length); + m_ContentId.Assign(buffer, content_id_length); + delete[] buffer; + + // rights issuer url + buffer = new char[rights_issuer_url_length]; + stream.Read(buffer, rights_issuer_url_length); + m_RightsIssuerUrl.Assign(buffer, rights_issuer_url_length); + delete[] buffer; + + // textual headers + buffer = new char[textual_headers_length]; + stream.Read(buffer, textual_headers_length); + m_TextualHeaders.SetData((AP4_Byte*)buffer, textual_headers_length); + delete[] buffer; + + // read the children + AP4_Size bytes_used = AP4_FULL_ATOM_HEADER_SIZE+1+1+8+2+2+2+content_id_length+rights_issuer_url_length+textual_headers_length; + if (bytes_used <= size) { + ReadChildren(atom_factory, stream, size-bytes_used); + } +} + +/*---------------------------------------------------------------------- +| AP4_OhdrAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OhdrAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_CHECK(stream.WriteUI08(m_EncryptionMethod)); + AP4_CHECK(stream.WriteUI08(m_PaddingScheme)); + AP4_CHECK(stream.WriteUI64(m_PlaintextLength)); + AP4_CHECK(stream.WriteUI16((AP4_UI16)m_ContentId.GetLength())); + AP4_CHECK(stream.WriteUI16((AP4_UI16)m_RightsIssuerUrl.GetLength())); + AP4_CHECK(stream.WriteUI16((AP4_UI16)m_TextualHeaders.GetDataSize())); + AP4_CHECK(stream.Write(m_ContentId.GetChars(), m_ContentId.GetLength())); + AP4_CHECK(stream.Write(m_RightsIssuerUrl.GetChars(), m_RightsIssuerUrl.GetLength())); + AP4_CHECK(stream.Write(m_TextualHeaders.GetData(), m_TextualHeaders.GetDataSize())); + + // write the children + return m_Children.Apply(AP4_AtomListWriter(stream)); +} + +/*---------------------------------------------------------------------- +| AP4_OhdrAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_OhdrAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("encryption_method", m_EncryptionMethod); + inspector.AddField("padding_scheme", m_PaddingScheme); + inspector.AddField("plaintext_length", (AP4_UI32)m_PlaintextLength); + inspector.AddField("content_id", m_ContentId.GetChars()); + inspector.AddField("rights_issuer_url", m_RightsIssuerUrl.GetChars()); + + { + AP4_DataBuffer output_buffer; + AP4_Result result; + + result = output_buffer.Reserve(1+m_TextualHeaders.GetDataSize()); + if (AP4_FAILED(result)) { + inspector.AddField("textual_headers", + m_TextualHeaders.UseData(), + m_TextualHeaders.GetDataSize(), + AP4_AtomInspector::HINT_HEX); + } else { + AP4_Size data_len = m_TextualHeaders.GetDataSize(); + AP4_Byte* textual_headers_string; + AP4_Byte* curr; + + output_buffer.SetData((const AP4_Byte*)m_TextualHeaders.GetData(), m_TextualHeaders.GetDataSize()); + curr = textual_headers_string = output_buffer.UseData(); + textual_headers_string[m_TextualHeaders.GetDataSize()] = '\0'; + while(curr < textual_headers_string+data_len) { + if ('\0' == *curr) { + *curr = '\n'; + } + curr++; + } + inspector.AddField("textual_headers", (const char*) textual_headers_string); + } + } + + return InspectChildren(inspector); +} + +/*---------------------------------------------------------------------- +| AP4_OhdrAtom::Clone ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_OhdrAtom::Clone() +{ + AP4_OhdrAtom* clone; + clone = new AP4_OhdrAtom(m_EncryptionMethod, + m_PaddingScheme, + m_PlaintextLength, + m_ContentId.GetChars(), + m_RightsIssuerUrl.GetChars(), + m_TextualHeaders.GetData(), + m_TextualHeaders.GetDataSize()); + + AP4_List<AP4_Atom>::Item* child_item = m_Children.FirstItem(); + while (child_item) { + AP4_Atom* child_clone = child_item->GetData()->Clone(); + if (child_clone) clone->AddChild(child_clone); + child_item = child_item->GetNext(); + } + + return clone; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OhdrAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OhdrAtom.h new file mode 100644 index 000000000..afee7f5fb --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OhdrAtom.h @@ -0,0 +1,104 @@ +/***************************************************************** +| +| AP4 - ohdr Atom +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_OHDR_ATOM_H_ +#define _AP4_OHDR_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4ContainerAtom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_OMA_DCF_ENCRYPTION_METHOD_NULL = 0; +const AP4_UI08 AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC = 1; +const AP4_UI08 AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR = 2; + +const AP4_UI08 AP4_OMA_DCF_PADDING_SCHEME_NONE = 0; +const AP4_UI08 AP4_OMA_DCF_PADDING_SCHEME_RFC_2630 = 1; + +/*---------------------------------------------------------------------- +| AP4_OhdrAtom ++---------------------------------------------------------------------*/ +class AP4_OhdrAtom : public AP4_ContainerAtom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_OhdrAtom, AP4_ContainerAtom) + + // class methods + static AP4_OhdrAtom* Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // constructor + AP4_OhdrAtom(AP4_UI08 encryption_method, + AP4_UI08 padding_scheme, + AP4_UI64 plaintext_length, + const char* content_id, + const char* rights_issuer_url, + const AP4_Byte* textual_headers, + AP4_Size textual_headers_size); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Atom* Clone(); + + // accessors + AP4_UI08 GetEncryptionMethod() const { return m_EncryptionMethod; } + void SetEncryptionMethod(AP4_UI08 encryption_method) { m_EncryptionMethod = encryption_method; } + AP4_UI08 GetPaddingScheme() const { return m_PaddingScheme; } + void SetPaddingScheme(AP4_UI08 padding_scheme) { m_PaddingScheme = padding_scheme; } + AP4_UI64 GetPlaintextLength() const { return m_PlaintextLength; } + const AP4_String& GetContentId() const { return m_ContentId; } + const AP4_String& GetRightsIssuerUrl() const { return m_RightsIssuerUrl; } + const AP4_DataBuffer& GetTextualHeaders() const { return m_TextualHeaders; } + +private: + // methods + AP4_OhdrAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // members + AP4_UI08 m_EncryptionMethod; + AP4_UI08 m_PaddingScheme; + AP4_UI64 m_PlaintextLength; + AP4_String m_ContentId; + AP4_String m_RightsIssuerUrl; + AP4_DataBuffer m_TextualHeaders; +}; + +#endif // _AP4_OHDR_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OmaDcf.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OmaDcf.cpp new file mode 100644 index 000000000..ea2cac242 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OmaDcf.cpp @@ -0,0 +1,1131 @@ +/*****************************************************************
+|
+| AP4 - OMA DCF Support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4SchmAtom.h"
+#include "Ap4StsdAtom.h"
+#include "Ap4Sample.h"
+#include "Ap4StreamCipher.h"
+#include "Ap4IsfmAtom.h"
+#include "Ap4FrmaAtom.h"
+#include "Ap4IkmsAtom.h"
+#include "Ap4IsfmAtom.h"
+#include "Ap4IsltAtom.h"
+#include "Ap4Utils.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4OdafAtom.h"
+#include "Ap4OmaDcf.h"
+#include "Ap4OhdrAtom.h"
+#include "Ap4OddaAtom.h"
+#include "Ap4OdheAtom.h"
+#include "Ap4FtypAtom.h"
+#include "Ap4GrpiAtom.h"
+#include "Ap4HdlrAtom.h"
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfAtomDecrypter::DecryptAtoms
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfAtomDecrypter::DecryptAtoms(AP4_AtomParent& atoms,
+ AP4_Processor::ProgressListener* /*listener*/,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ProtectionKeyMap& key_map)
+{
+ unsigned int index = 1;
+ for (AP4_List<AP4_Atom>::Item* item = atoms.GetChildren().FirstItem();
+ item;
+ item = item->GetNext()) {
+ AP4_Atom* atom = item->GetData();
+ if (atom->GetType() != AP4_ATOM_TYPE_ODRM) continue;
+
+ // check that we have the key
+ const AP4_UI08* key = key_map.GetKey(index++);
+ if (key == NULL) return AP4_ERROR_INVALID_PARAMETERS;
+
+ // check that we have all the atoms we need
+ AP4_ContainerAtom* odrm = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
+ if (odrm == NULL) continue; // not enough info
+ AP4_OdheAtom* odhe = AP4_DYNAMIC_CAST(AP4_OdheAtom, odrm->GetChild(AP4_ATOM_TYPE_ODHE));
+ if (odhe == NULL) continue; // not enough info
+ AP4_OddaAtom* odda = AP4_DYNAMIC_CAST(AP4_OddaAtom, odrm->GetChild(AP4_ATOM_TYPE_ODDA));;
+ if (odda == NULL) continue; // not enough info
+ AP4_OhdrAtom* ohdr = AP4_DYNAMIC_CAST(AP4_OhdrAtom, odhe->GetChild(AP4_ATOM_TYPE_OHDR));
+ if (ohdr == NULL) continue; // not enough info
+
+ // do nothing if the atom is not encrypted
+ if (ohdr->GetEncryptionMethod() == AP4_OMA_DCF_ENCRYPTION_METHOD_NULL) {
+ continue;
+ }
+
+ // create the byte stream
+ AP4_ByteStream* cipher_stream = NULL;
+ AP4_Result result = CreateDecryptingStream(*odrm,
+ key,
+ 16,
+ block_cipher_factory,
+ cipher_stream);
+ if (AP4_SUCCEEDED(result)) {
+ // replace the odda atom's payload with the decrypted stream
+ odda->SetEncryptedPayload(*cipher_stream, ohdr->GetPlaintextLength());
+ cipher_stream->Release();
+
+ // the atom will now be in the clear
+ ohdr->SetEncryptionMethod(AP4_OMA_DCF_ENCRYPTION_METHOD_NULL);
+ ohdr->SetPaddingScheme(AP4_OMA_DCF_PADDING_SCHEME_NONE);
+ }
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfAtomDecrypter::CreateDecryptingStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfAtomDecrypter::CreateDecryptingStream(
+ AP4_ContainerAtom& odrm,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream)
+{
+ // default return values
+ stream = NULL;
+
+ AP4_OdheAtom* odhe = AP4_DYNAMIC_CAST(AP4_OdheAtom, odrm.GetChild(AP4_ATOM_TYPE_ODHE));
+ if (odhe == NULL) return AP4_ERROR_INVALID_FORMAT;
+ AP4_OddaAtom* odda = AP4_DYNAMIC_CAST(AP4_OddaAtom, odrm.GetChild(AP4_ATOM_TYPE_ODDA));;
+ if (odda == NULL) return AP4_ERROR_INVALID_FORMAT;
+ AP4_OhdrAtom* ohdr = AP4_DYNAMIC_CAST(AP4_OhdrAtom, odhe->GetChild(AP4_ATOM_TYPE_OHDR));
+ if (ohdr == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // shortcut for non-encrypted files
+ if (ohdr->GetEncryptionMethod() == AP4_OMA_DCF_ENCRYPTION_METHOD_NULL) {
+ stream = &odda->GetEncryptedPayload();
+ stream->AddReference();
+ return AP4_SUCCESS;
+ }
+
+ // if this is part of a group, use the group key to obtain the content
+ // key (note that the field called GroupKey in the spec is actually not
+ // the group key but the content key encrypted with the group key...
+ AP4_GrpiAtom* grpi = AP4_DYNAMIC_CAST(AP4_GrpiAtom, ohdr->GetChild(AP4_ATOM_TYPE_GRPI));
+ AP4_UI08* key_buffer = NULL;
+ if (grpi) {
+ // sanity check on the encrypted key size
+ if (grpi->GetGroupKey().GetDataSize() < 32) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // create a block cipher to decrypt the content key
+ AP4_BlockCipher* block_cipher = NULL;
+ AP4_Result result;
+
+ // create a stream cipher from the block cipher
+ AP4_StreamCipher* stream_cipher = NULL;
+ switch (ohdr->GetEncryptionMethod()) {
+ case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC:
+ result = block_cipher_factory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::DECRYPT,
+ key,
+ key_size,
+ block_cipher);
+ if (AP4_FAILED(result)) return result;
+ stream_cipher = new AP4_CbcStreamCipher(block_cipher, AP4_CbcStreamCipher::DECRYPT);
+ break;
+
+ case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR:
+ result = block_cipher_factory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::ENCRYPT,
+ key,
+ key_size,
+ block_cipher);
+ if (AP4_FAILED(result)) return result;
+ stream_cipher = new AP4_CtrStreamCipher(block_cipher, NULL, 16);
+ break;
+
+ default:
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+
+ // set the IV
+ stream_cipher->SetIV(grpi->GetGroupKey().GetData());
+
+ // decrypt the content key
+ AP4_Size key_buffer_size = grpi->GetGroupKey().GetDataSize(); // worst case
+ key_buffer = new AP4_UI08[key_buffer_size];
+ result = stream_cipher->ProcessBuffer(grpi->GetGroupKey().GetData()+16,
+ grpi->GetGroupKey().GetDataSize()-16,
+ key_buffer,
+ &key_buffer_size,
+ true);
+ delete stream_cipher; // this will also delete the block cipher
+ if (AP4_FAILED(result)) {
+ delete[] key_buffer;
+ return result;
+ }
+
+ // point to the new key value
+ key = key_buffer;
+ key_size = key_buffer_size;
+ }
+
+ AP4_OmaDcfCipherMode mode;
+ switch (ohdr->GetEncryptionMethod()) {
+ case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC:
+ mode = AP4_OMA_DCF_CIPHER_MODE_CBC;
+ break;
+ case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR:
+ mode = AP4_OMA_DCF_CIPHER_MODE_CTR;
+ break;
+ default:
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+
+ AP4_Result result;
+ result = CreateDecryptingStream(mode,
+ odda->GetEncryptedPayload(),
+ ohdr->GetPlaintextLength(),
+ key, key_size,
+ block_cipher_factory,
+ stream);
+
+ // cleanup
+ delete[] key_buffer;
+
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfAtomDecrypter::CreateDecryptingStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfAtomDecrypter::CreateDecryptingStream(
+ AP4_OmaDcfCipherMode mode,
+ AP4_ByteStream& encrypted_stream,
+ AP4_LargeSize cleartext_size,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream)
+{
+ // default return value
+ stream = NULL;
+
+ // get the encrypted size (includes IV and padding)
+ AP4_LargeSize encrypted_size = 0;
+ AP4_Result result = encrypted_stream.GetSize(encrypted_size);
+ if (AP4_FAILED(result)) return result;
+
+ // check that the encrypted size is consistent with the cipher mode
+ AP4_DecryptingStream::CipherMode cipher_mode;
+ if (mode == AP4_OMA_DCF_CIPHER_MODE_CBC) {
+ // we need at least 16 bytes of IV and 32 bytes of data+padding
+ // we also need a multiple of the block size
+ if (encrypted_size < 48 || ((encrypted_size % 16) != 0)) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+ cipher_mode = AP4_DecryptingStream::CIPHER_MODE_CBC;
+ } else if (mode == AP4_OMA_DCF_CIPHER_MODE_CTR) {
+ // we need at least 16 bytes of IV
+ if (encrypted_size < 16) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+ cipher_mode = AP4_DecryptingStream::CIPHER_MODE_CTR;
+ } else {
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+
+ // read the IV
+ AP4_UI08 iv[16];
+ result = encrypted_stream.Seek(0);
+ if (AP4_FAILED(result)) return result;
+ result = encrypted_stream.Read(iv, 16);
+ if (AP4_FAILED(result)) return result;
+
+ // create a sub stream with just the encrypted payload without the IV
+ AP4_ByteStream* sub_stream = new AP4_SubStream(encrypted_stream, 16, encrypted_size-16);
+
+ // create the decrypting cipher
+ result = AP4_DecryptingStream::Create(cipher_mode,
+ *sub_stream,
+ cleartext_size,
+ iv,
+ 16,
+ key,
+ key_size,
+ block_cipher_factory,
+ stream);
+
+ // we don't keep our own reference to the sub stream
+ sub_stream->Release();
+
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfSampleDecrypter::Create
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfSampleDecrypter::Create(AP4_ProtectedSampleDescription* sample_description,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_OmaDcfSampleDecrypter*& cipher)
+{
+ // check the parameters
+ if (key == NULL || block_cipher_factory == NULL) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+
+ // default return value
+ cipher = NULL;
+
+ // get the scheme info atom
+ AP4_ContainerAtom* schi = sample_description->GetSchemeInfo()->GetSchiAtom();
+ if (schi == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // get and check the cipher params
+ // NOTE: we only support an IV Length less than or equal to the cipher block size,
+ // and we don't know how to deal with a key indicator length != 0
+ AP4_OdafAtom* odaf = AP4_DYNAMIC_CAST(AP4_OdafAtom, schi->FindChild("odkm/odaf"));
+ if (odaf) {
+ if (odaf->GetIvLength() > AP4_CIPHER_BLOCK_SIZE) return AP4_ERROR_INVALID_FORMAT;
+ if (odaf->GetKeyIndicatorLength() != 0) return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // check the scheme details and create the cipher
+ AP4_OhdrAtom* ohdr = AP4_DYNAMIC_CAST(AP4_OhdrAtom, schi->FindChild("odkm/ohdr"));
+ if (ohdr == NULL) return AP4_ERROR_INVALID_FORMAT;
+ AP4_UI08 encryption_method = ohdr->GetEncryptionMethod();
+ if (encryption_method == AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC) {
+ // in CBC mode, we only support IVs of the same size as the cipher block size
+ if (odaf->GetIvLength() != AP4_CIPHER_BLOCK_SIZE) return AP4_ERROR_INVALID_FORMAT;
+
+ // require RFC_2630 padding
+ if (ohdr->GetPaddingScheme() != AP4_OMA_DCF_PADDING_SCHEME_RFC_2630) {
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+
+ // create the block cipher
+ AP4_BlockCipher* block_cipher = NULL;
+ AP4_Result result = block_cipher_factory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::DECRYPT,
+ key,
+ key_size,
+ block_cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // create the cipher
+ cipher = new AP4_OmaDcfCbcSampleDecrypter(block_cipher,
+ odaf->GetSelectiveEncryption());
+ return AP4_SUCCESS;
+ } else if (encryption_method == AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR) {
+ // require NONE padding
+ if (ohdr->GetPaddingScheme() != AP4_OMA_DCF_PADDING_SCHEME_NONE) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // create the block cipher
+ AP4_BlockCipher* block_cipher = NULL;
+ AP4_Result result = block_cipher_factory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::ENCRYPT,
+ key,
+ key_size,
+ block_cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // create the cipher
+ cipher = new AP4_OmaDcfCtrSampleDecrypter(block_cipher,
+ odaf->GetIvLength(),
+ odaf->GetSelectiveEncryption());
+ return AP4_SUCCESS;
+ } else {
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleDecrypter::AP4_OmaDcfCtrSampleDecrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCtrSampleDecrypter::AP4_OmaDcfCtrSampleDecrypter(
+ AP4_BlockCipher* block_cipher,
+ AP4_Size iv_length,
+ bool selective_encryption) :
+ AP4_OmaDcfSampleDecrypter(iv_length, selective_encryption)
+{
+ m_Cipher = new AP4_CtrStreamCipher(block_cipher, NULL, iv_length);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleDecrypter::~AP4_OmaDcfCtrSampleDecrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCtrSampleDecrypter::~AP4_OmaDcfCtrSampleDecrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ const AP4_UI08* /*iv*/)
+{
+ bool is_encrypted = true;
+ const unsigned char* in = data_in.GetData();
+ AP4_Size in_size = data_in.GetDataSize();
+
+ // default to 0 output
+ AP4_CHECK(data_out.SetDataSize(0));
+
+ // check the selective encryption flag
+ if (m_SelectiveEncryption) {
+ if (in_size < 1) return AP4_ERROR_INVALID_FORMAT;
+ is_encrypted = ((in[0]&0x80)!=0);
+ in++;
+ }
+
+ // check the size
+ unsigned int header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
+ if (header_size > in_size) return AP4_ERROR_INVALID_FORMAT;
+
+ // process the sample data
+ AP4_Size payload_size = in_size-header_size;
+ AP4_CHECK(data_out.Reserve(payload_size));
+ unsigned char* out = data_out.UseData();
+ if (is_encrypted) {
+ // set the IV
+ m_Cipher->SetIV(in);
+ AP4_CHECK(m_Cipher->ProcessBuffer(in+m_IvLength,
+ payload_size,
+ out));
+ } else {
+ AP4_CopyMemory(out, in, payload_size);
+ }
+ AP4_CHECK(data_out.SetDataSize(payload_size));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleDecrypter::GetDecryptedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_OmaDcfCtrSampleDecrypter::GetDecryptedSampleSize(AP4_Sample& sample)
+{
+ if (m_Cipher == NULL) return 0;
+
+ // decide if this sample is encrypted or not
+ bool is_encrypted;
+ if (m_SelectiveEncryption) {
+ // read the first byte to see if the sample is encrypted or not
+ AP4_Byte h;
+ AP4_DataBuffer peek_buffer;
+ peek_buffer.SetBuffer(&h, 1);
+ sample.ReadData(peek_buffer, 1);
+ is_encrypted = ((h&0x80)!=0);
+ } else {
+ is_encrypted = true;
+ }
+
+ AP4_Size crypto_header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
+ return sample.GetSize()-crypto_header_size;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleDecrypter::AP4_OmaDcfCbcSampleDecrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCbcSampleDecrypter::AP4_OmaDcfCbcSampleDecrypter(
+ AP4_BlockCipher* block_cipher,
+ bool selective_encryption) :
+ AP4_OmaDcfSampleDecrypter(AP4_CIPHER_BLOCK_SIZE, selective_encryption)
+{
+ m_Cipher = new AP4_CbcStreamCipher(block_cipher, AP4_CbcStreamCipher::DECRYPT);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleDecrypter::~AP4_OmaDcfCbcSampleDecrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCbcSampleDecrypter::~AP4_OmaDcfCbcSampleDecrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDbcCbcSampleDecrypter::DecryptSampleData
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfCbcSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ const AP4_UI08* /*iv*/)
+{
+ bool is_encrypted = true;
+ const unsigned char* in = data_in.GetData();
+ AP4_Size in_size = data_in.GetDataSize();
+ AP4_Size out_size;
+
+ // default to 0 output
+ AP4_CHECK(data_out.SetDataSize(0));
+
+ // check the selective encryption flag
+ if (m_SelectiveEncryption) {
+ if (in_size < 1) return AP4_ERROR_INVALID_FORMAT;
+ is_encrypted = ((in[0]&0x80)!=0);
+ in++;
+ }
+
+ // check the size
+ unsigned int header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
+ if (header_size > in_size) return AP4_ERROR_INVALID_FORMAT;
+
+ // process the sample data
+ unsigned int payload_size = in_size-header_size;
+ data_out.Reserve(payload_size);
+ unsigned char* out = data_out.UseData();
+ if (is_encrypted) {
+ // get the IV
+ const AP4_UI08* iv = (const AP4_UI08*)in;
+ in += AP4_CIPHER_BLOCK_SIZE;
+
+ m_Cipher->SetIV(iv);
+ out_size = payload_size;
+ AP4_CHECK(m_Cipher->ProcessBuffer(in, payload_size, out, &out_size, true));
+ } else {
+ AP4_CopyMemory(out, in, payload_size);
+ out_size = payload_size;
+ }
+
+ AP4_CHECK(data_out.SetDataSize(out_size));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleDecrypter::GetDecryptedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_OmaDcfCbcSampleDecrypter::GetDecryptedSampleSize(AP4_Sample& sample)
+{
+ if (m_Cipher == NULL) return 0;
+
+ // decide if this sample is encrypted or not
+ bool is_encrypted;
+ if (m_SelectiveEncryption) {
+ // read the first byte to see if the sample is encrypted or not
+ AP4_Byte h;
+ AP4_DataBuffer peek_buffer;
+ peek_buffer.SetBuffer(&h, 1);
+ sample.ReadData(peek_buffer, 1);
+ is_encrypted = ((h&0x80)!=0);
+ } else {
+ is_encrypted = true;
+ }
+
+ if (is_encrypted) {
+ // with CBC, we need to decrypt the last block to know what the padding was
+ AP4_Size crypto_header_size = (m_SelectiveEncryption?1:0)+m_IvLength;
+ AP4_Size encrypted_size = sample.GetSize()-crypto_header_size;
+ AP4_DataBuffer encrypted;
+ AP4_DataBuffer decrypted;
+ AP4_Size decrypted_size = AP4_CIPHER_BLOCK_SIZE;
+ if (sample.GetSize() < crypto_header_size+AP4_CIPHER_BLOCK_SIZE) {
+ return 0;
+ }
+ AP4_Size offset = sample.GetSize()-2*AP4_CIPHER_BLOCK_SIZE;
+ if (AP4_FAILED(sample.ReadData(encrypted, 2*AP4_CIPHER_BLOCK_SIZE, offset))) {
+ return 0;
+ }
+ decrypted.Reserve(decrypted_size);
+ m_Cipher->SetIV(encrypted.GetData());
+ if (AP4_FAILED(m_Cipher->ProcessBuffer(encrypted.GetData()+AP4_CIPHER_BLOCK_SIZE,
+ AP4_CIPHER_BLOCK_SIZE,
+ decrypted.UseData(),
+ &decrypted_size,
+ true))) {
+ return 0;
+ }
+ unsigned int padding_size = AP4_CIPHER_BLOCK_SIZE-decrypted_size;
+ return encrypted_size-padding_size;
+ } else {
+ return sample.GetSize()-(m_SelectiveEncryption?1:0);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfSampleEncrypter::AP4_OmaDcfSampleEncrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfSampleEncrypter::AP4_OmaDcfSampleEncrypter(const AP4_UI08* salt)
+{
+ // left-align the salt
+ unsigned int i=0;
+ if (salt) {
+ for (; i<8; i++) {
+ m_Salt[i] = salt[i];
+ }
+ }
+ for (; i<sizeof(m_Salt)/sizeof(m_Salt[0]); i++) {
+ m_Salt[i] = 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleEncrypter::AP4_OmaDcfCtrSampleEncrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCtrSampleEncrypter::AP4_OmaDcfCtrSampleEncrypter(AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt) :
+ AP4_OmaDcfSampleEncrypter(salt)
+{
+ m_Cipher = new AP4_CtrStreamCipher(block_cipher, m_Salt, 8);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleEncrypter::~AP4_OmaDcfCtrSampleEncrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCtrSampleEncrypter::~AP4_OmaDcfCtrSampleEncrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleEncrypter::EncryptSampleData
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ AP4_UI64 counter,
+ bool /*skip_encryption*/)
+{
+ // setup the buffers
+ const unsigned char* in = data_in.GetData();
+ AP4_CHECK(data_out.SetDataSize(data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE+1));
+ unsigned char* out = data_out.UseData();
+
+ // selective encryption flag
+ *out++ = 0x80;
+
+ // IV on 16 bytes: [SSSSSSSSXXXXXXXX]
+ // where SSSSSSSS is the 64-bit salt and
+ // XXXXXXXX is the 64-bit base counter
+ AP4_CopyMemory(out, m_Salt, 8);
+ AP4_BytesFromUInt64BE(&out[8], counter);
+
+ // encrypt the payload
+ AP4_Size data_size = data_in.GetDataSize();
+ m_Cipher->SetIV(out+8);
+ m_Cipher->ProcessBuffer(in, data_size, out+AP4_CIPHER_BLOCK_SIZE);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleEncrypter::GetEncryptedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_OmaDcfCtrSampleEncrypter::GetEncryptedSampleSize(AP4_Sample& sample)
+{
+ return sample.GetSize()+AP4_CIPHER_BLOCK_SIZE+1;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleEncrypter::AP4_OmaDcfCbcSampleEncrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCbcSampleEncrypter::AP4_OmaDcfCbcSampleEncrypter(AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt) :
+ AP4_OmaDcfSampleEncrypter(salt)
+{
+ m_Cipher = new AP4_CbcStreamCipher(block_cipher, AP4_CbcStreamCipher::ENCRYPT);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleEncrypter::~AP4_OmaDcfCbcSampleEncrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfCbcSampleEncrypter::~AP4_OmaDcfCbcSampleEncrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleEncrypter::EncryptSampleData
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfCbcSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ AP4_UI64 counter,
+ bool /*skip_encryption*/)
+{
+ // make sure there is enough space in the output buffer
+ data_out.Reserve(data_in.GetDataSize()+2*AP4_CIPHER_BLOCK_SIZE+1);
+
+ // setup the buffers
+ AP4_Size out_size = data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE;
+ unsigned char* out = data_out.UseData();
+
+ // selective encryption flag
+ *out++ = 0x80;
+
+ // IV on 16 bytes: [SSSSSSSSXXXXXXXX]
+ // where SSSSSSSS is the 64-bit salt and
+ // XXXXXXXX is the 64-bit base counter
+ AP4_CopyMemory(out, m_Salt, 8);
+ AP4_BytesFromUInt64BE(&out[8], counter);
+
+ // encrypt the payload
+ m_Cipher->SetIV(out);
+ m_Cipher->ProcessBuffer(data_in.GetData(),
+ data_in.GetDataSize(),
+ out+AP4_CIPHER_BLOCK_SIZE,
+ &out_size,
+ true);
+ AP4_CHECK(data_out.SetDataSize(out_size+AP4_CIPHER_BLOCK_SIZE+1));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleEncrypter::GetEncryptedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_OmaDcfCbcSampleEncrypter::GetEncryptedSampleSize(AP4_Sample& sample)
+{
+ AP4_Size sample_size = sample.GetSize();
+ AP4_Size padding_size = AP4_CIPHER_BLOCK_SIZE-(sample_size%AP4_CIPHER_BLOCK_SIZE);
+ return sample_size+padding_size+AP4_CIPHER_BLOCK_SIZE+1;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackDecrypter::Create
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfTrackDecrypter::Create(
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_ProtectedSampleDescription* sample_description,
+ AP4_SampleEntry* sample_entry,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_OmaDcfTrackDecrypter*& decrypter)
+{
+ // check and set defaults
+ if (key == NULL) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+ if (block_cipher_factory == NULL) {
+ block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
+ }
+ decrypter = NULL;
+
+ // create the cipher
+ AP4_OmaDcfSampleDecrypter* cipher = NULL;
+ AP4_Result result = AP4_OmaDcfSampleDecrypter::Create(sample_description,
+ key,
+ key_size,
+ block_cipher_factory,
+ cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // instantiate the object
+ decrypter = new AP4_OmaDcfTrackDecrypter(cipher,
+ sample_entry,
+ sample_description->GetOriginalFormat());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackDecrypter::AP4_OmaDcfTrackDecrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfTrackDecrypter::AP4_OmaDcfTrackDecrypter(AP4_OmaDcfSampleDecrypter* cipher,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 original_format) :
+ m_Cipher(cipher),
+ m_SampleEntry(sample_entry),
+ m_OriginalFormat(original_format)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackDecrypter::~AP4_OmaDcfTrackDecrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfTrackDecrypter::~AP4_OmaDcfTrackDecrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackDecrypter::GetProcessedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_OmaDcfTrackDecrypter::GetProcessedSampleSize(AP4_Sample& sample)
+{
+ if (m_Cipher == NULL) return 0;
+ return m_Cipher->GetDecryptedSampleSize(sample);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackDecrypter::ProcessTrack
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfTrackDecrypter::ProcessTrack()
+{
+ m_SampleEntry->SetType(m_OriginalFormat);
+ m_SampleEntry->DeleteChild(AP4_ATOM_TYPE_SINF);
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfDecrypter::ProcessSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfTrackDecrypter::ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out)
+{
+ return m_Cipher->DecryptSampleData(data_in, data_out);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackEncrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfTrackEncrypter : public AP4_Processor::TrackHandler {
+public:
+ // constructor
+ AP4_OmaDcfTrackEncrypter(AP4_OmaDcfCipherMode cipher_mode,
+ AP4_BlockCipher* block_cipher,
+ const AP4_UI08* iv,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 format,
+ const char* content_id,
+ const char* rights_issuer_url,
+ const AP4_Byte* textual_headers,
+ AP4_Size textual_headers_size);
+ virtual ~AP4_OmaDcfTrackEncrypter();
+
+ // methods
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample);
+ virtual AP4_Result ProcessTrack();
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out);
+
+private:
+ // members
+ AP4_OmaDcfSampleEncrypter* m_Cipher;
+ AP4_UI08 m_CipherMode;
+ AP4_UI08 m_CipherPadding;
+ AP4_SampleEntry* m_SampleEntry;
+ AP4_UI32 m_Format;
+ AP4_String m_ContentId;
+ AP4_String m_RightsIssuerUrl;
+ AP4_DataBuffer m_TextualHeaders;
+ AP4_UI64 m_Counter;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackEncrypter::AP4_OmaDcfTrackEncrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfTrackEncrypter::AP4_OmaDcfTrackEncrypter(
+ AP4_OmaDcfCipherMode cipher_mode,
+ AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 format,
+ const char* content_id,
+ const char* rights_issuer_url,
+ const AP4_Byte* textual_headers,
+ AP4_Size textual_headers_size) :
+ m_SampleEntry(sample_entry),
+ m_Format(format),
+ m_ContentId(content_id),
+ m_RightsIssuerUrl(rights_issuer_url),
+ m_TextualHeaders(textual_headers, textual_headers_size),
+ m_Counter(0)
+{
+ // instantiate the cipher (fixed params for now)
+ if (cipher_mode == AP4_OMA_DCF_CIPHER_MODE_CBC) {
+ m_Cipher = new AP4_OmaDcfCbcSampleEncrypter(block_cipher, salt);
+ m_CipherMode = AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC;
+ m_CipherPadding = AP4_OMA_DCF_PADDING_SCHEME_RFC_2630;
+ } else {
+ m_Cipher = new AP4_OmaDcfCtrSampleEncrypter(block_cipher, salt);
+ m_CipherMode = AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR;
+ m_CipherPadding = AP4_OMA_DCF_PADDING_SCHEME_NONE;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackEncrypter::~AP4_OmaDcfTrackEncrypter
++---------------------------------------------------------------------*/
+AP4_OmaDcfTrackEncrypter::~AP4_OmaDcfTrackEncrypter()
+{
+ delete m_Cipher;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackEncrypter::GetProcessedSampleSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_OmaDcfTrackEncrypter::GetProcessedSampleSize(AP4_Sample& sample)
+{
+ return m_Cipher->GetEncryptedSampleSize(sample);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackEncrypter::ProcessTrack
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfTrackEncrypter::ProcessTrack()
+{
+ // sinf container
+ AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF);
+
+ // original format
+ AP4_FrmaAtom* frma = new AP4_FrmaAtom(m_SampleEntry->GetType());
+
+ // scheme info
+ AP4_ContainerAtom* schi = new AP4_ContainerAtom(AP4_ATOM_TYPE_SCHI);
+ AP4_OdafAtom* odaf = new AP4_OdafAtom(true, 0, AP4_CIPHER_BLOCK_SIZE);
+ AP4_OhdrAtom* ohdr = new AP4_OhdrAtom(m_CipherMode,
+ m_CipherPadding,
+ 0,
+ m_ContentId.GetChars(),
+ m_RightsIssuerUrl.GetChars(),
+ m_TextualHeaders.GetData(),
+ m_TextualHeaders.GetDataSize());
+ AP4_ContainerAtom* odkm = new AP4_ContainerAtom(AP4_ATOM_TYPE_ODKM, (AP4_UI32)0, (AP4_UI32)0);
+ AP4_SchmAtom* schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_OMA,
+ AP4_PROTECTION_SCHEME_VERSION_OMA_20);
+ odkm->AddChild(odaf);
+ odkm->AddChild(ohdr);
+
+ // populate the schi container
+ schi->AddChild(odkm);
+
+ // populate the sinf container
+ sinf->AddChild(frma);
+ sinf->AddChild(schm);
+ sinf->AddChild(schi);
+
+ // add the sinf atom to the sample description
+ m_SampleEntry->AddChild(sinf);
+
+ // change the atom type of the sample description
+ m_SampleEntry->SetType(m_Format);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackEncrypter::ProcessSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfTrackEncrypter::ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out)
+{
+ AP4_Result result = m_Cipher->EncryptSampleData(data_in,
+ data_out,
+ m_Counter,
+ false);
+ if (AP4_FAILED(result)) return result;
+
+ m_Counter += (data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE-1)/AP4_CIPHER_BLOCK_SIZE;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfDecryptingProcessor:AP4_OmaDcfDecryptingProcessor
++---------------------------------------------------------------------*/
+AP4_OmaDcfDecryptingProcessor::AP4_OmaDcfDecryptingProcessor(
+ const AP4_ProtectionKeyMap* key_map /* = NULL */,
+ AP4_BlockCipherFactory* block_cipher_factory /* = NULL */)
+{
+ if (key_map) {
+ // copy the keys
+ m_KeyMap.SetKeys(*key_map);
+ }
+
+ if (block_cipher_factory == NULL) {
+ m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
+ } else {
+ m_BlockCipherFactory = block_cipher_factory;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfDecryptingProcessor:Initialize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfDecryptingProcessor::Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& /* stream */,
+ ProgressListener* listener)
+{
+ // decide which processor to instantiate based on the file type
+ AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
+ if (ftyp) {
+ if (ftyp->GetMajorBrand() == AP4_OMA_DCF_BRAND_ODCF || ftyp->HasCompatibleBrand(AP4_OMA_DCF_BRAND_ODCF)) {
+ return AP4_OmaDcfAtomDecrypter::DecryptAtoms(top_level, listener, m_BlockCipherFactory, m_KeyMap);
+ } else {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+ } else {
+ return AP4_SUCCESS;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfEncryptingProcessor:AP4_OmaDcfEncryptingProcessor
++---------------------------------------------------------------------*/
+AP4_OmaDcfEncryptingProcessor::AP4_OmaDcfEncryptingProcessor(AP4_OmaDcfCipherMode cipher_mode,
+ AP4_BlockCipherFactory* block_cipher_factory) :
+ m_CipherMode(cipher_mode)
+{
+ if (block_cipher_factory == NULL) {
+ m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
+ } else {
+ m_BlockCipherFactory = block_cipher_factory;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfEncryptingProcessor::Initialize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_OmaDcfEncryptingProcessor::Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& /*stream*/,
+ AP4_Processor::ProgressListener* /*listener*/)
+{
+ AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
+ if (ftyp) {
+ // remove the atom, it will be replaced with a new one
+ top_level.RemoveChild(ftyp);
+
+ // keep the existing brand and compatible brands
+ AP4_Array<AP4_UI32> compatible_brands;
+ compatible_brands.EnsureCapacity(ftyp->GetCompatibleBrands().ItemCount()+1);
+ for (unsigned int i=0; i<ftyp->GetCompatibleBrands().ItemCount(); i++) {
+ compatible_brands.Append(ftyp->GetCompatibleBrands()[i]);
+ }
+
+ // add the OMA compatible brand if it is not already there
+ if (!ftyp->HasCompatibleBrand(AP4_OMA_DCF_BRAND_OPF2)) {
+ compatible_brands.Append(AP4_OMA_DCF_BRAND_OPF2);
+ }
+
+ // create a replacement
+ AP4_FtypAtom* new_ftyp = new AP4_FtypAtom(ftyp->GetMajorBrand(),
+ ftyp->GetMinorVersion(),
+ &compatible_brands[0],
+ compatible_brands.ItemCount());
+ delete ftyp;
+ ftyp = new_ftyp;
+ } else {
+ AP4_UI32 opf2 = AP4_OMA_DCF_BRAND_OPF2;
+ ftyp = new AP4_FtypAtom(AP4_FTYP_BRAND_ISOM, 0, &opf2, 1);
+ }
+
+ // insert the ftyp atom as the first child
+ return top_level.AddChild(ftyp, 0);
+}
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfEncryptingProcessor:CreateTrackHandler
++---------------------------------------------------------------------*/
+AP4_Processor::TrackHandler*
+AP4_OmaDcfEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
+{
+ // find the stsd atom
+ AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
+
+ // avoid tracks with no stsd atom (should not happen)
+ if (stsd == NULL) return NULL;
+
+ // only look at the first sample description
+ AP4_SampleEntry* entry = stsd->GetSampleEntry(0);
+ if (entry == NULL) return NULL;
+
+ // create a handler for this track if we have a key for it and we know
+ // how to map the type
+ const AP4_UI08* key;
+ const AP4_UI08* iv;
+ AP4_UI32 format = 0;
+ if (AP4_SUCCEEDED(m_KeyMap.GetKeyAndIv(trak->GetId(), key, iv))) {
+ switch (entry->GetType()) {
+ case AP4_ATOM_TYPE_MP4A:
+ format = AP4_ATOM_TYPE_ENCA;
+ break;
+
+ case AP4_ATOM_TYPE_MP4V:
+ case AP4_ATOM_TYPE_AVC1:
+ format = AP4_ATOM_TYPE_ENCV;
+ break;
+
+ default: {
+ // try to find if this is audio or video
+ AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, trak->FindChild("mdia/hdlr"));
+ if (hdlr) {
+ switch (hdlr->GetHandlerType()) {
+ case AP4_HANDLER_TYPE_SOUN:
+ format = AP4_ATOM_TYPE_ENCA;
+ break;
+
+ case AP4_HANDLER_TYPE_VIDE:
+ format = AP4_ATOM_TYPE_ENCV;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (format) {
+ const char* content_id = m_PropertyMap.GetProperty(trak->GetId(), "ContentId");
+ const char* rights_issuer_url = m_PropertyMap.GetProperty(trak->GetId(), "RightsIssuerUrl");
+ AP4_DataBuffer textual_headers;
+ AP4_Result result = m_PropertyMap.GetTextualHeaders(trak->GetId(), textual_headers);
+ if (AP4_FAILED(result)) textual_headers.SetDataSize(0);
+
+ // create the block cipher
+ AP4_BlockCipher* block_cipher = NULL;
+ result = m_BlockCipherFactory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::ENCRYPT,
+ key,
+ AP4_CIPHER_BLOCK_SIZE,
+ block_cipher);
+ if (AP4_FAILED(result)) return NULL;
+ return new AP4_OmaDcfTrackEncrypter(m_CipherMode,
+ block_cipher,
+ iv,
+ entry,
+ format,
+ content_id,
+ rights_issuer_url,
+ textual_headers.GetData(),
+ textual_headers.GetDataSize());
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OmaDcf.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OmaDcf.h new file mode 100644 index 000000000..806f6f0db --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4OmaDcf.h @@ -0,0 +1,322 @@ +/*****************************************************************
+|
+| AP4 - OMA DCF support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+#ifndef _AP4_OMA_DCF_H_
+#define _AP4_OMA_DCF_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4SampleEntry.h"
+#include "Ap4Atom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4SampleDescription.h"
+#include "Ap4Processor.h"
+#include "Ap4Protection.h"
+
+/*----------------------------------------------------------------------
+| class references
++---------------------------------------------------------------------*/
+class AP4_OdafAtom;
+class AP4_StreamCipher;
+class AP4_CbcStreamCipher;
+class AP4_CtrStreamCipher;
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_OMA = AP4_ATOM_TYPE('o','d','k','m');
+const AP4_UI32 AP4_PROTECTION_SCHEME_VERSION_OMA_20 = 0x00000200;
+const AP4_UI32 AP4_OMA_DCF_BRAND_ODCF = AP4_ATOM_TYPE('o','d','c','f');
+const AP4_UI32 AP4_OMA_DCF_BRAND_OPF2 = AP4_ATOM_TYPE('o','p','f','2');
+
+typedef enum {
+ AP4_OMA_DCF_CIPHER_MODE_CTR,
+ AP4_OMA_DCF_CIPHER_MODE_CBC
+} AP4_OmaDcfCipherMode;
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfAtomDecrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfAtomDecrypter {
+public:
+ // class methods
+ static AP4_Result DecryptAtoms(AP4_AtomParent& atoms,
+ AP4_Processor::ProgressListener* listener,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ProtectionKeyMap& key_map);
+
+ // Returns a byte stream that will produce the decrypted data found
+ // in the 'odda' child atom of an 'odrm' atom
+ static AP4_Result CreateDecryptingStream(AP4_ContainerAtom& odrm_atom,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream);
+
+ // Returns a byte stream that will produce the decrypted data from
+ // an encrypted stream where the IV follows the encrypted bytes.
+ // This method is normally not called directly: most callers will call
+ // the stream factory that takes an 'odrm' atom as an input parameter
+ static AP4_Result CreateDecryptingStream(AP4_OmaDcfCipherMode mode,
+ AP4_ByteStream& encrypted_stream,
+ AP4_LargeSize cleartext_size,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream);
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfSampleDecrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfSampleDecrypter : public AP4_SampleDecrypter
+{
+public:
+ // factory
+ static AP4_Result Create(AP4_ProtectedSampleDescription* sample_description,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_OmaDcfSampleDecrypter*& cipher);
+
+ // constructor and destructor
+ AP4_OmaDcfSampleDecrypter(AP4_Size iv_length,
+ bool selective_encryption) :
+ m_IvLength(iv_length),
+ m_SelectiveEncryption(selective_encryption) {}
+
+protected:
+ AP4_Size m_IvLength;
+ AP4_Size m_KeyIndicatorLength;
+ bool m_SelectiveEncryption;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleDecrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfCtrSampleDecrypter : public AP4_OmaDcfSampleDecrypter
+{
+public:
+ // constructor and destructor
+ AP4_OmaDcfCtrSampleDecrypter(AP4_BlockCipher* block_cipher,
+ AP4_Size iv_length,
+ bool selective_encryption);
+ ~AP4_OmaDcfCtrSampleDecrypter();
+
+ // methods
+ virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ const AP4_UI08* iv = NULL);
+ virtual AP4_Size GetDecryptedSampleSize(AP4_Sample& sample);
+
+private:
+ // members
+ AP4_CtrStreamCipher* m_Cipher;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleDecrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfCbcSampleDecrypter : public AP4_OmaDcfSampleDecrypter
+{
+public:
+ // constructor and destructor
+ AP4_OmaDcfCbcSampleDecrypter(AP4_BlockCipher* block_cipher,
+ bool selective_encryption);
+ ~AP4_OmaDcfCbcSampleDecrypter();
+
+ // methods
+ virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ const AP4_UI08* iv = NULL);
+ virtual AP4_Size GetDecryptedSampleSize(AP4_Sample& sample);
+
+private:
+ // members
+ AP4_CbcStreamCipher* m_Cipher;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfTrackDecrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfTrackDecrypter : public AP4_Processor::TrackHandler {
+public:
+ // constructor
+ static AP4_Result Create(const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_ProtectedSampleDescription* sample_description,
+ AP4_SampleEntry* sample_entry,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_OmaDcfTrackDecrypter*& decrypter);
+ virtual ~AP4_OmaDcfTrackDecrypter();
+
+ // methods
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample);
+ virtual AP4_Result ProcessTrack();
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out);
+
+private:
+ // constructor
+ AP4_OmaDcfTrackDecrypter(AP4_OmaDcfSampleDecrypter* cipher,
+ AP4_SampleEntry* sample_entry,
+ AP4_UI32 original_format);
+
+ // members
+ AP4_OmaDcfSampleDecrypter* m_Cipher;
+ AP4_SampleEntry* m_SampleEntry;
+ AP4_UI32 m_OriginalFormat;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfSampleEncrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfSampleEncrypter
+{
+public:
+ // constructor and destructor
+ AP4_OmaDcfSampleEncrypter(const AP4_UI08* salt); // salt is only 8 bytes
+ virtual ~AP4_OmaDcfSampleEncrypter() {}
+
+ // methods
+ virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ AP4_UI64 bso,
+ bool skip_encryption) = 0;
+ virtual AP4_Size GetEncryptedSampleSize(AP4_Sample& sample) = 0;
+
+protected:
+ // members
+ AP4_UI08 m_Salt[16];
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCtrSampleEncrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfCtrSampleEncrypter : public AP4_OmaDcfSampleEncrypter
+{
+public:
+ // constructor and destructor
+ AP4_OmaDcfCtrSampleEncrypter(AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt); // salt is only 8 bytes
+ ~AP4_OmaDcfCtrSampleEncrypter();
+
+ // methods
+ virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ AP4_UI64 bso,
+ bool skip_encryption);
+ virtual AP4_Size GetEncryptedSampleSize(AP4_Sample& sample);
+
+private:
+ // members
+ AP4_CtrStreamCipher* m_Cipher;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfCbcSampleEncrypter
++---------------------------------------------------------------------*/
+class AP4_OmaDcfCbcSampleEncrypter : public AP4_OmaDcfSampleEncrypter
+{
+public:
+ // constructor and destructor
+ AP4_OmaDcfCbcSampleEncrypter(AP4_BlockCipher* block_cipher,
+ const AP4_UI08* salt); // salt is only 8 bytes
+ ~AP4_OmaDcfCbcSampleEncrypter();
+
+ // methods
+ virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ AP4_UI64 bso,
+ bool skip_encryption);
+ virtual AP4_Size GetEncryptedSampleSize(AP4_Sample& sample);
+
+private:
+ // members
+ AP4_CbcStreamCipher* m_Cipher;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfDecryptingProcessor
++---------------------------------------------------------------------*/
+/**
+ * Use for DCF only, not PDCF. For PDCF, use the
+ * AP4_StandardDecryptingProcessor class
+ */
+class AP4_OmaDcfDecryptingProcessor : public AP4_Processor
+{
+public:
+ // constructor
+ AP4_OmaDcfDecryptingProcessor(const AP4_ProtectionKeyMap* key_map = NULL,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+
+ // accessors
+ AP4_ProtectionKeyMap& GetKeyMap() { return m_KeyMap; }
+
+ // methods
+ virtual AP4_Result Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ ProgressListener* listener);
+
+private:
+ // members
+ AP4_BlockCipherFactory* m_BlockCipherFactory;
+ AP4_ProtectionKeyMap m_KeyMap;
+};
+
+/*----------------------------------------------------------------------
+| AP4_OmaDcfEncryptingProcessor
++---------------------------------------------------------------------*/
+class AP4_OmaDcfEncryptingProcessor : public AP4_Processor
+{
+public:
+ // constructor
+ AP4_OmaDcfEncryptingProcessor(AP4_OmaDcfCipherMode cipher_mode,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+
+ // accessors
+ AP4_ProtectionKeyMap& GetKeyMap() { return m_KeyMap; }
+ AP4_TrackPropertyMap& GetPropertyMap() { return m_PropertyMap; }
+
+ // AP4_Processor methods
+ virtual AP4_Result Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ AP4_Processor::ProgressListener* listener = NULL);
+ virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
+
+private:
+ // members
+ AP4_OmaDcfCipherMode m_CipherMode;
+ AP4_BlockCipherFactory* m_BlockCipherFactory;
+ AP4_ProtectionKeyMap m_KeyMap;
+ AP4_TrackPropertyMap m_PropertyMap;
+};
+
+#endif // _AP4_OMA_DCF_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Piff.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Piff.cpp new file mode 100644 index 000000000..f442658ff --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Piff.cpp @@ -0,0 +1,1144 @@ +/***************************************************************** +| +| AP4 - PIFF Support +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SchmAtom.h" +#include "Ap4StsdAtom.h" +#include "Ap4Sample.h" +#include "Ap4StreamCipher.h" +#include "Ap4IsfmAtom.h" +#include "Ap4FrmaAtom.h" +#include "Ap4IsfmAtom.h" +#include "Ap4IsltAtom.h" +#include "Ap4Utils.h" +#include "Ap4TrakAtom.h" +#include "Ap4Piff.h" +#include "Ap4FtypAtom.h" +#include "Ap4HdlrAtom.h" +#include "Ap4TrunAtom.h" +#include "Ap4TfhdAtom.h" +#include "Ap4Marlin.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +AP4_UI08 const AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM[16] = { + 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51, 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54 +}; +AP4_UI08 const AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM[16] = { + 0xA2, 0x39, 0x4F, 0x52, 0x5A, 0x9B, 0x4f, 0x14, 0xA2, 0x44, 0x6C, 0x42, 0x7C, 0x64, 0x8D, 0xF4 +}; + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleEncrypter::AP4_PiffCtrSampleEncrypter ++---------------------------------------------------------------------*/ +AP4_PiffCtrSampleEncrypter::AP4_PiffCtrSampleEncrypter(AP4_BlockCipher* block_cipher) +{ + m_Cipher = new AP4_CtrStreamCipher(block_cipher, NULL, 0); +} + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleEncrypter::EncryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& /*data_in */, + AP4_DataBuffer& /*data_out*/) +{ + return AP4_ERROR_NOT_SUPPORTED; // FIXME: not implemented yet +} + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleEncrypter::~AP4_PiffCtrSampleEncrypter ++---------------------------------------------------------------------*/ +AP4_PiffCtrSampleEncrypter::~AP4_PiffCtrSampleEncrypter() +{ + delete m_Cipher; +} + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCtrSampleEncrypter::EncryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffAvcCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& /*data_in */, + AP4_DataBuffer& /*data_out*/) +{ + return AP4_ERROR_NOT_SUPPORTED; // FIXME: not implemented yet +} + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleEncrypter::AP4_PiffCbcSampleEncrypter ++---------------------------------------------------------------------*/ +AP4_PiffCbcSampleEncrypter::AP4_PiffCbcSampleEncrypter(AP4_BlockCipher* block_cipher) +{ + m_Cipher = new AP4_CbcStreamCipher(block_cipher, AP4_StreamCipher::ENCRYPT); +} + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleEncrypter::EncryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffCbcSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out) +{ + // the output has the same size as the input + data_out.SetDataSize(data_in.GetDataSize()); + + // setup direct pointers to the buffers + const AP4_UI08* in = data_in.GetData(); + AP4_UI08* out = data_out.UseData(); + + // setup the IV + m_Cipher->SetIV(m_Iv); + + // process the sample data + unsigned int block_count = data_in.GetDataSize()/16; + if (block_count) { + AP4_Size out_size = data_out.GetDataSize(); + AP4_Result result = m_Cipher->ProcessBuffer(in, block_count*16, out, &out_size, false); + if (AP4_FAILED(result)) return result; + in += block_count*16; + out += block_count*16; + + // update the IV (last cipherblock emitted) + AP4_CopyMemory(m_Iv, out-16, 16); + } + + // any partial block at the end remains in the clear + unsigned int partial = data_in.GetDataSize()%16; + if (partial) { + AP4_CopyMemory(out, in, partial); + } + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleEncrypter::~AP4_PiffCbcSampleEncrypter ++---------------------------------------------------------------------*/ +AP4_PiffCbcSampleEncrypter::~AP4_PiffCbcSampleEncrypter() +{ + delete m_Cipher; +} + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCbcSampleEncrypter::EncryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffAvcCbcSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out) +{ + // the output has the same size as the input + data_out.SetDataSize(data_in.GetDataSize()); + + // check some basics + if (data_in.GetDataSize() == 0) return AP4_SUCCESS; + + // setup direct pointers to the buffers + const AP4_UI08* in = data_in.GetData(); + AP4_UI08* out = data_out.UseData(); + + // setup the IV + m_Cipher->SetIV(m_Iv); + + // process the sample data, one NALU at a time + const AP4_UI08* in_end = data_in.GetData()+data_in.GetDataSize(); + while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) { + unsigned int nalu_length; + switch (m_NaluLengthSize) { + case 1: + nalu_length = *in; + break; + + case 2: + nalu_length = AP4_BytesToUInt16BE(in); + break; + + case 4: + nalu_length = AP4_BytesToUInt32BE(in); + break; + + default: + return AP4_ERROR_INVALID_FORMAT; + } + + unsigned int chunk_size = m_NaluLengthSize+nalu_length; + unsigned int cleartext_size = chunk_size%16; + unsigned int block_count = chunk_size/16; + if (cleartext_size < m_NaluLengthSize+1) { + AP4_ASSERT(block_count); + --block_count; + cleartext_size += 16; + } + + // copy the cleartext portion + AP4_CopyMemory(out, in, cleartext_size); + + // encrypt the rest + if (block_count) { + AP4_Size out_size = block_count*16; + m_Cipher->ProcessBuffer(in+cleartext_size, block_count*16, out+cleartext_size, &out_size, false); + } + + // move the pointers + in += chunk_size; + out += chunk_size; + } + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncrypter ++---------------------------------------------------------------------*/ +class AP4_PiffTrackEncrypter : public AP4_Processor::TrackHandler { +public: + // constructor + AP4_PiffTrackEncrypter(AP4_UI32 default_algorithm_id, + AP4_UI08 default_iv_size, + const AP4_UI08* default_kid, + AP4_SampleEntry* sample_entry, + AP4_UI32 format); + + // methods + virtual AP4_Result ProcessTrack(); + virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out); + +private: + // members + AP4_SampleEntry* m_SampleEntry; + AP4_UI32 m_Format; + AP4_UI32 m_DefaultAlgorithmId; + AP4_UI08 m_DefaultIvSize; + AP4_UI08 m_DefaultKid[16]; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncrypter::AP4_PiffTrackEncrypter ++---------------------------------------------------------------------*/ +AP4_PiffTrackEncrypter::AP4_PiffTrackEncrypter( + AP4_UI32 default_algorithm_id, + AP4_UI08 default_iv_size, + const AP4_UI08* default_kid, + AP4_SampleEntry* sample_entry, + AP4_UI32 format) : + m_SampleEntry(sample_entry), + m_Format(format), + m_DefaultAlgorithmId(default_algorithm_id), + m_DefaultIvSize(default_iv_size) +{ + // copy the KID + AP4_CopyMemory(m_DefaultKid, default_kid, 16); +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncrypter::ProcessTrack ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffTrackEncrypter::ProcessTrack() +{ + // sinf container + AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF); + + // original format + AP4_FrmaAtom* frma = new AP4_FrmaAtom(m_SampleEntry->GetType()); + + // scheme info + AP4_ContainerAtom* schi = new AP4_ContainerAtom(AP4_ATOM_TYPE_SCHI); + AP4_SchmAtom* schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_PIFF, + AP4_PROTECTION_SCHEME_VERSION_PIFF_10); + AP4_PiffTrackEncryptionAtom* piff_enc = + new AP4_PiffTrackEncryptionAtom(m_DefaultAlgorithmId, + m_DefaultIvSize, + m_DefaultKid); + schi->AddChild(piff_enc); + + // populate the sinf container + sinf->AddChild(frma); + sinf->AddChild(schm); + sinf->AddChild(schi); + + // add the sinf atom to the sample description + m_SampleEntry->AddChild(sinf); + + // change the atom type of the sample description + m_SampleEntry->SetType(m_Format); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncrypter::ProcessSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffTrackEncrypter::ProcessSample(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out) +{ + return data_out.SetData(data_in.GetData(), data_in.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| AP4_PiffFragmentEncrypter ++---------------------------------------------------------------------*/ +class AP4_PiffFragmentEncrypter : public AP4_Processor::FragmentHandler { +public: + // constructor + AP4_PiffFragmentEncrypter(AP4_ContainerAtom* traf, + AP4_PiffEncryptingProcessor::Encrypter* encrypter); + + // methods + virtual AP4_Result ProcessFragment(); + virtual AP4_Result FinishFragment(); + virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out); + +private: + // members + AP4_ContainerAtom* m_Traf; + AP4_PiffSampleEncryptionAtom* m_SampleEncryptionAtom; + AP4_PiffEncryptingProcessor::Encrypter* m_Encrypter; + AP4_Ordinal m_IvIndex; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffFragmentEncrypter::AP4_PiffFragmentEncrypter ++---------------------------------------------------------------------*/ +AP4_PiffFragmentEncrypter::AP4_PiffFragmentEncrypter(AP4_ContainerAtom* traf, + AP4_PiffEncryptingProcessor::Encrypter* encrypter) : + m_Traf(traf), + m_SampleEncryptionAtom(NULL), + m_Encrypter(encrypter), + m_IvIndex(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_PiffFragmentEncrypter::ProcessFragment ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffFragmentEncrypter::ProcessFragment() +{ + // count the number of samples and create IVs + unsigned int sample_count = 0; + for (AP4_List<AP4_Atom>::Item* item = m_Traf->GetChildren().FirstItem(); + item; + item = item->GetNext()) { + AP4_Atom* child = item->GetData(); + if (child->GetType() == AP4_ATOM_TYPE_TRUN) { + AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, child); + if (trun) { + sample_count += trun->GetEntries().ItemCount(); + } + } + } + + // create a sample encryption atom + m_SampleEncryptionAtom = new AP4_PiffSampleEncryptionAtom(sample_count); + + // add the atom to the traf container + m_Traf->AddChild(m_SampleEncryptionAtom); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffFragmentEncrypter::FinishFragment ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffFragmentEncrypter::FinishFragment() +{ + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffFragmentEncrypter::ProcessSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffFragmentEncrypter::ProcessSample(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out) +{ + // store the IV for this sample + m_SampleEncryptionAtom->SetIv(m_IvIndex++, m_Encrypter->m_SampleEncrypter->GetIv()); + + // encrypt the sample + AP4_Result result = m_Encrypter->m_SampleEncrypter->EncryptSampleData(data_in, data_out); + return result; +} + +/*---------------------------------------------------------------------- +| AP4_PiffEncryptingProcessor:AP4_PiffEncryptingProcessor ++---------------------------------------------------------------------*/ +AP4_PiffEncryptingProcessor::AP4_PiffEncryptingProcessor(AP4_PiffCipherMode cipher_mode, + AP4_BlockCipherFactory* block_cipher_factory) : + m_CipherMode(cipher_mode) +{ + // create a block cipher factory if none is given + if (block_cipher_factory == NULL) { + m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance; + } else { + m_BlockCipherFactory = block_cipher_factory; + } +} + +/*---------------------------------------------------------------------- +| AP4_PiffEncryptingProcessor:~AP4_PiffEncryptingProcessor ++---------------------------------------------------------------------*/ +AP4_PiffEncryptingProcessor::~AP4_PiffEncryptingProcessor() +{ + m_Encrypters.DeleteReferences(); +} + +/*---------------------------------------------------------------------- +| AP4_PiffEncryptingProcessor::Initialize ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffEncryptingProcessor::Initialize(AP4_AtomParent& top_level, + AP4_ByteStream& /*stream*/, + AP4_Processor::ProgressListener* /*listener*/) +{ + AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP)); + if (ftyp) { + // remove the atom, it will be replaced with a new one + top_level.RemoveChild(ftyp); + + // keep the existing brand and compatible brands + AP4_Array<AP4_UI32> compatible_brands; + compatible_brands.EnsureCapacity(ftyp->GetCompatibleBrands().ItemCount()+1); + for (unsigned int i=0; i<ftyp->GetCompatibleBrands().ItemCount(); i++) { + compatible_brands.Append(ftyp->GetCompatibleBrands()[i]); + } + + // add the OMA compatible brand if it is not already there + if (!ftyp->HasCompatibleBrand(AP4_PIFF_BRAND)) { + compatible_brands.Append(AP4_PIFF_BRAND); + } + + // create a replacement + AP4_FtypAtom* new_ftyp = new AP4_FtypAtom(ftyp->GetMajorBrand(), + ftyp->GetMinorVersion(), + &compatible_brands[0], + compatible_brands.ItemCount()); + delete ftyp; + ftyp = new_ftyp; + } else { + AP4_UI32 piff = AP4_PIFF_BRAND; + ftyp = new AP4_FtypAtom(AP4_FTYP_BRAND_ISOM, 0, &piff, 1); + } + + // insert the ftyp atom as the first child + return top_level.AddChild(ftyp, 0); +} + +/*---------------------------------------------------------------------- +| AP4_PiffEncryptingProcessor:CreateTrackHandler ++---------------------------------------------------------------------*/ +AP4_Processor::TrackHandler* +AP4_PiffEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak) +{ + // find the stsd atom + AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd")); + + // avoid tracks with no stsd atom (should not happen) + if (stsd == NULL) return NULL; + + // only look at the first sample description + AP4_SampleEntry* entry = stsd->GetSampleEntry(0); + if (entry == NULL) return NULL; + + // create a handler for this track if we have a key for it and we know + // how to map the type + const AP4_UI08* key; + const AP4_UI08* iv; + if (AP4_FAILED(m_KeyMap.GetKeyAndIv(trak->GetId(), key, iv))) { + return NULL; + } + + AP4_UI32 format = 0; + switch (entry->GetType()) { + case AP4_ATOM_TYPE_MP4A: + format = AP4_ATOM_TYPE_ENCA; + break; + + case AP4_ATOM_TYPE_MP4V: + case AP4_ATOM_TYPE_AVC1: + format = AP4_ATOM_TYPE_ENCV; + break; + + default: { + // try to find if this is audio or video + AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, trak->FindChild("mdia/hdlr")); + if (hdlr) { + switch (hdlr->GetHandlerType()) { + case AP4_HANDLER_TYPE_SOUN: + format = AP4_ATOM_TYPE_ENCA; + break; + + case AP4_HANDLER_TYPE_VIDE: + format = AP4_ATOM_TYPE_ENCV; + break; + } + } + break; + } + } + if (format == 0) return NULL; + + // get the track properties + AP4_UI08 kid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + const char* kid_hex = m_PropertyMap.GetProperty(trak->GetId(), "KID"); + if (kid_hex && AP4_StringLength(kid_hex) == 32) { + AP4_ParseHex(kid_hex, kid, 16); + } + + // create the encrypter + AP4_Processor::TrackHandler* track_encrypter; + track_encrypter = new AP4_PiffTrackEncrypter(m_CipherMode == AP4_PIFF_CIPHER_MODE_CBC?AP4_PIFF_ALGORITHM_ID_CBC:AP4_PIFF_ALGORITHM_ID_CTR, + 16, + kid, + entry, + format); + + // create a block cipher + AP4_BlockCipher* block_cipher = NULL; + AP4_Result result = m_BlockCipherFactory->Create(AP4_BlockCipher::AES_128, + AP4_BlockCipher::ENCRYPT, + key, + 16, + block_cipher); + if (AP4_FAILED(result)) return NULL; + + // add a new cipher state for this track + AP4_PiffSampleEncrypter* sample_encrypter = NULL; + switch (m_CipherMode) { + case AP4_PIFF_CIPHER_MODE_CBC: + if (entry->GetType() == AP4_ATOM_TYPE_AVC1) { + AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entry->GetChild(AP4_ATOM_TYPE_AVCC)); + if (avcc == NULL) return NULL; + sample_encrypter = new AP4_PiffAvcCbcSampleEncrypter(block_cipher, avcc->GetNaluLengthSize()); + } else { + sample_encrypter = new AP4_PiffCbcSampleEncrypter(block_cipher); + } + break; + + case AP4_PIFF_CIPHER_MODE_CTR: + if (entry->GetType() == AP4_ATOM_TYPE_AVC1) { + AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, entry->GetChild(AP4_ATOM_TYPE_AVCC)); + if (avcc == NULL) return NULL; + sample_encrypter = new AP4_PiffAvcCtrSampleEncrypter(block_cipher, avcc->GetNaluLengthSize()); + } else { + sample_encrypter = new AP4_PiffCtrSampleEncrypter(block_cipher); + } + break; + } + sample_encrypter->SetIv(iv); + m_Encrypters.Add(new Encrypter(trak->GetId(), sample_encrypter)); + + return track_encrypter; +} + +/*---------------------------------------------------------------------- +| AP4_PiffEncryptingProcessor:CreateFragmentHandler ++---------------------------------------------------------------------*/ +AP4_Processor::FragmentHandler* +AP4_PiffEncryptingProcessor::CreateFragmentHandler(AP4_ContainerAtom* traf) +{ + // get the traf header (tfhd) for this track fragment so we can get the track ID + AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD)); + if (tfhd == NULL) return NULL; + + // lookup the encrypter for this track + Encrypter* encrypter = NULL; + for (AP4_List<Encrypter>::Item* item = m_Encrypters.FirstItem(); + item; + item = item->GetNext()) { + if (item->GetData()->m_TrackId == tfhd->GetTrackId()) { + encrypter = item->GetData(); + break; + } + } + if (encrypter == NULL) return NULL; + return new AP4_PiffFragmentEncrypter(traf, encrypter); +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleDecrypter::Create ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffSampleDecrypter::Create(AP4_ProtectedSampleDescription* sample_description, + AP4_ContainerAtom* traf, + const AP4_UI08* key, + AP4_Size key_size, + AP4_BlockCipherFactory* block_cipher_factory, + AP4_PiffSampleDecrypter*& decrypter) +{ + // check the parameters + if (key == NULL || block_cipher_factory == NULL) { + return AP4_ERROR_INVALID_PARAMETERS; + } + + // default return value + decrypter = NULL; + + // check the sample description + if (sample_description->GetSchemeType() != AP4_PROTECTION_SCHEME_TYPE_PIFF) { + return AP4_ERROR_INVALID_PARAMETERS; + } + + // get the scheme info atom + AP4_ContainerAtom* schi = sample_description->GetSchemeInfo()->GetSchiAtom(); + if (schi == NULL) return AP4_ERROR_INVALID_FORMAT; + + // look for a track encryption atom + AP4_PiffTrackEncryptionAtom* track_encryption_atom = + AP4_DYNAMIC_CAST(AP4_PiffTrackEncryptionAtom, schi->GetChild(AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM)); + + // look for a sample encryption atom + AP4_PiffSampleEncryptionAtom* sample_encryption_atom = NULL; + if (traf) { + sample_encryption_atom = AP4_DYNAMIC_CAST(AP4_PiffSampleEncryptionAtom, traf->GetChild(AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM)); + if (sample_encryption_atom == NULL) return AP4_ERROR_INVALID_FORMAT; + } + + // create the block cipher needed to decrypt the samples + AP4_UI32 algorithm_id; + unsigned int iv_size; + if (sample_encryption_atom && + sample_encryption_atom->GetFlags() & AP4_PIFF_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) { + algorithm_id = sample_encryption_atom->GetAlgorithmId(); + iv_size = sample_encryption_atom->GetIvSize(); + } else { + if (track_encryption_atom == NULL) return AP4_ERROR_INVALID_FORMAT; + algorithm_id = track_encryption_atom->GetDefaultAlgorithmId(); + iv_size = track_encryption_atom->GetDefaultIvSize(); + } + switch (algorithm_id) { + case AP4_PIFF_ALGORITHM_ID_NONE: + decrypter = new AP4_PiffNullSampleDecrypter(); + break; + + case AP4_PIFF_ALGORITHM_ID_CTR: + if (iv_size != 8 && iv_size != 16) { + return AP4_ERROR_INVALID_FORMAT; + } else { + // create the block cipher + AP4_BlockCipher* block_cipher = NULL; + AP4_Result result = block_cipher_factory->Create(AP4_BlockCipher::AES_128, + AP4_BlockCipher::ENCRYPT, + key, + key_size, + block_cipher); + if (AP4_FAILED(result)) return result; + + // create the decrypter + if (sample_description->GetOriginalFormat() == AP4_ATOM_TYPE_AVC1) { + AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, sample_description->GetOriginalSampleDescription()); + if (avc_desc == NULL) { + return AP4_ERROR_INVALID_FORMAT; + } + decrypter = new AP4_PiffAvcCbcSampleDecrypter(block_cipher, + sample_encryption_atom, + avc_desc->GetNaluLengthSize()); + + } else { + decrypter = new AP4_PiffCbcSampleDecrypter(block_cipher, + sample_encryption_atom); + } + } + break; + + case AP4_PIFF_ALGORITHM_ID_CBC: + if (iv_size != 16) { + return AP4_ERROR_INVALID_FORMAT; + } else { + // create the block cipher + AP4_BlockCipher* block_cipher = NULL; + AP4_Result result = block_cipher_factory->Create(AP4_BlockCipher::AES_128, + AP4_BlockCipher::DECRYPT, + key, + key_size, + block_cipher); + if (AP4_FAILED(result)) return result; + + // create the decrypter + if (sample_description->GetOriginalFormat() == AP4_ATOM_TYPE_AVC1) { + AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, sample_description->GetOriginalSampleDescription()); + if (avc_desc == NULL) { + return AP4_ERROR_INVALID_FORMAT; + } + decrypter = new AP4_PiffAvcCbcSampleDecrypter(block_cipher, + sample_encryption_atom, + avc_desc->GetNaluLengthSize()); + } else { + decrypter = new AP4_PiffCbcSampleDecrypter(block_cipher, + sample_encryption_atom); + } + } + break; + + default: + return AP4_ERROR_NOT_SUPPORTED; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleDecrypter::SetSampleIndex ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffSampleDecrypter::SetSampleIndex(AP4_Ordinal sample_index) +{ + if (sample_index < m_SampleEncryptionAtom->GetIvCount()) { + return AP4_ERROR_OUT_OF_RANGE; + } + m_SampleIndex = sample_index; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleDecrypter::AP4_PiffCtrSampleDecrypter ++---------------------------------------------------------------------*/ +AP4_PiffCtrSampleDecrypter::AP4_PiffCtrSampleDecrypter( + AP4_BlockCipher* block_cipher, + AP4_Size iv_size, + AP4_PiffSampleEncryptionAtom* sample_encryption_atom) : + AP4_PiffSampleDecrypter(sample_encryption_atom), + m_IvSize(iv_size) +{ + m_Cipher = new AP4_CtrStreamCipher(block_cipher, NULL, iv_size); +} + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleDecrypter::~AP4_PiffCtrSampleDecrypter ++---------------------------------------------------------------------*/ +AP4_PiffCtrSampleDecrypter::~AP4_PiffCtrSampleDecrypter() +{ + delete m_Cipher; +} + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleDecrypter::DecryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffCtrSampleDecrypter::DecryptSampleData(AP4_DataBuffer& /*data_in */, + AP4_DataBuffer& /*data_out*/, + const AP4_UI08* /*iv */) +{ + return AP4_ERROR_NOT_SUPPORTED; // FIXME: not implemented yet +} + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCtrSampleDecrypter::DecryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffAvcCtrSampleDecrypter::DecryptSampleData(AP4_DataBuffer& /*data_in */, + AP4_DataBuffer& /*data_out*/, + const AP4_UI08* /*iv */) +{ + return AP4_ERROR_NOT_SUPPORTED; // FIXME: not implemented yet +} + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleDecrypter::AP4_PiffCbcSampleDecrypter ++---------------------------------------------------------------------*/ +AP4_PiffCbcSampleDecrypter::AP4_PiffCbcSampleDecrypter( + AP4_BlockCipher* block_cipher, + AP4_PiffSampleEncryptionAtom* sample_encryption_atom) : + AP4_PiffSampleDecrypter(sample_encryption_atom) +{ + m_Cipher = new AP4_CbcStreamCipher(block_cipher, AP4_CbcStreamCipher::DECRYPT); +} + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleDecrypter::~AP4_PiffCbcSampleDecrypter ++---------------------------------------------------------------------*/ +AP4_PiffCbcSampleDecrypter::~AP4_PiffCbcSampleDecrypter() +{ + delete m_Cipher; +} + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleDecrypter::DecryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffCbcSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + const AP4_UI08* iv) +{ + // the output has the same size as the input + data_out.SetDataSize(data_in.GetDataSize()); + + // setup direct pointers to the buffers + const AP4_UI08* in = data_in.GetData(); + AP4_UI08* out = data_out.UseData(); + + // setup the IV + if (iv == NULL) { + if (m_SampleEncryptionAtom == NULL) return AP4_ERROR_INVALID_PARAMETERS; + iv = m_SampleEncryptionAtom->GetIv(m_SampleIndex); + if (iv == NULL) return AP4_ERROR_INVALID_FORMAT; + } + m_Cipher->SetIV(iv); + + // process the sample data + unsigned int block_count = data_in.GetDataSize()/16; + if (block_count) { + AP4_Size out_size = data_out.GetDataSize(); + AP4_Result result = m_Cipher->ProcessBuffer(in, block_count*16, out, &out_size, false); + if (AP4_FAILED(result)) return result; + AP4_ASSERT(out_size == block_count*16); + in += block_count*16; + out += block_count*16; + } + + // any partial block at the end remains in the clear + unsigned int partial = data_in.GetDataSize()%16; + if (partial) { + AP4_CopyMemory(out, in, partial); + } + + // move on to the next sample + ++m_SampleIndex; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCbcSampleDecrypter::DecryptSampleData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffAvcCbcSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + const AP4_UI08* iv) +{ + // the output has the same size as the input + data_out.SetDataSize(data_in.GetDataSize()); + + // setup direct pointers to the buffers + const AP4_UI08* in = data_in.GetData(); + AP4_UI08* out = data_out.UseData(); + + // setup the IV + if (iv == NULL) { + if (m_SampleEncryptionAtom == NULL) return AP4_ERROR_INVALID_PARAMETERS; + iv = m_SampleEncryptionAtom->GetIv(m_SampleIndex); + if (iv == NULL) return AP4_ERROR_INVALID_FORMAT; + } + m_Cipher->SetIV(iv); + + // process the sample data, one NALU at a time + const AP4_UI08* in_end = data_in.GetData()+data_in.GetDataSize(); + while ((AP4_Size)(in_end-in) > 1+m_NaluLengthSize) { + unsigned int nalu_length; + switch (m_NaluLengthSize) { + case 1: + nalu_length = *in; + break; + + case 2: + nalu_length = AP4_BytesToUInt16BE(in); + break; + + case 4: + nalu_length = AP4_BytesToUInt32BE(in); + break; + + default: + return AP4_ERROR_INVALID_FORMAT; + } + + unsigned int chunk_size = m_NaluLengthSize+nalu_length; + unsigned int cleartext_size = chunk_size%16; + unsigned int block_count = chunk_size/16; + if (cleartext_size < m_NaluLengthSize+1) { + AP4_ASSERT(block_count); + --block_count; + cleartext_size += 16; + } + + // copy the cleartext portion + AP4_CopyMemory(out, in, cleartext_size); + + // encrypt the rest + if (block_count) { + AP4_Size out_size = block_count*16; + m_Cipher->ProcessBuffer(in+cleartext_size, block_count*16, out+cleartext_size, &out_size, false); + } + + // move the pointers + in += chunk_size; + out += chunk_size; + } + + // move on to the next sample + ++m_SampleIndex; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncryptionAtom::Create ++---------------------------------------------------------------------*/ +AP4_PiffTrackEncryptionAtom* +AP4_PiffTrackEncryptionAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version = 0; + AP4_UI32 flags = 0; + AP4_Result result = ReadFullHeader(stream, version, flags); + if (AP4_FAILED(result)) return NULL; + if (version != 0) return NULL; + return new AP4_PiffTrackEncryptionAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncryptionAtom::AP4_PiffTrackEncryptionAtom ++---------------------------------------------------------------------*/ +AP4_PiffTrackEncryptionAtom::AP4_PiffTrackEncryptionAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_UuidAtom(size, AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, version, flags) +{ + stream.ReadUI24(m_DefaultAlgorithmId); + stream.ReadUI08(m_DefaultIvSize); + stream.Read (m_DefaultKid, 16); +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncryptionAtom::AP4_PiffTrackEncryptionAtom ++---------------------------------------------------------------------*/ +AP4_PiffTrackEncryptionAtom::AP4_PiffTrackEncryptionAtom(AP4_UI32 default_algorithm_id, + AP4_UI08 default_iv_size, + const AP4_UI08* default_kid) : + AP4_UuidAtom(AP4_FULL_UUID_ATOM_HEADER_SIZE+20, AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM, 0, 0), + m_DefaultAlgorithmId(default_algorithm_id), + m_DefaultIvSize(default_iv_size) +{ + AP4_CopyMemory(m_DefaultKid, default_kid, 16); +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncryptionAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffTrackEncryptionAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("default_AlgorithmID", m_DefaultAlgorithmId); + inspector.AddField("default_IV_size", m_DefaultIvSize); + inspector.AddField("default_KID", m_DefaultKid, 16); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncryptionAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffTrackEncryptionAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the fields + result = stream.WriteUI24(m_DefaultAlgorithmId); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI08(m_DefaultIvSize); + if (AP4_FAILED(result)) return result; + result = stream.Write(m_DefaultKid, 16); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::Create ++---------------------------------------------------------------------*/ +AP4_PiffSampleEncryptionAtom* +AP4_PiffSampleEncryptionAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version = 0; + AP4_UI32 flags = 0; + AP4_Result result = ReadFullHeader(stream, version, flags); + if (AP4_FAILED(result)) return NULL; + if (version != 0) return NULL; + return new AP4_PiffSampleEncryptionAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::AP4_PiffSampleEncryptionAtom ++---------------------------------------------------------------------*/ +AP4_PiffSampleEncryptionAtom::AP4_PiffSampleEncryptionAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_UuidAtom(size, AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM, version, flags) +{ + if (flags & AP4_PIFF_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) { + stream.ReadUI24(m_AlgorithmId); + stream.ReadUI08(m_IvSize); + stream.Read (m_Kid, 16); + } else { + m_AlgorithmId = 0; + m_IvSize = 0; + AP4_SetMemory(m_Kid, 0, 16); + } + + stream.ReadUI32(m_IvCount); + + // NOTE: the problem here is that we don't know the IV size when flags==0 + // So what we do is read the whole atom and assume that there's nothing + // else after the table. + AP4_Size payload_size = size-GetHeaderSize()-4; + if ((flags & AP4_PIFF_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) == 0) { + if (m_IvCount) { + m_IvSize = (AP4_UI08)(payload_size/m_IvCount); + } + } + m_Ivs.SetDataSize(payload_size); + stream.Read(m_Ivs.UseData(), payload_size); +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::AP4_PiffSampleEncryptionAtom ++---------------------------------------------------------------------*/ +AP4_PiffSampleEncryptionAtom::AP4_PiffSampleEncryptionAtom(AP4_Cardinal sample_count) : + AP4_UuidAtom(AP4_FULL_UUID_ATOM_HEADER_SIZE+4+sample_count*16, AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM, 0, 0), + m_AlgorithmId(0), + m_IvSize(16), + m_IvCount(sample_count) +{ + AP4_SetMemory(m_Kid, 0, 16); + + // initialize the IVs to 0s + m_Ivs.SetDataSize(sample_count*m_IvSize); + AP4_SetMemory(m_Ivs.UseData(), 0, m_Ivs.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::AP4_PiffSampleEncryptionAtom ++---------------------------------------------------------------------*/ +AP4_PiffSampleEncryptionAtom::AP4_PiffSampleEncryptionAtom(AP4_UI32 algorithm_id, + AP4_UI08 iv_size, + const AP4_UI08* kid, + AP4_Cardinal sample_count) : + AP4_UuidAtom(AP4_FULL_UUID_ATOM_HEADER_SIZE+20+4, AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM, 0, + AP4_PIFF_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS), + m_AlgorithmId(algorithm_id), + m_IvSize(iv_size), + m_IvCount(sample_count) +{ + AP4_CopyMemory(m_Kid, kid, 16); + + // initialize the IVs to 0s + m_Ivs.SetDataSize(sample_count*m_IvSize); + AP4_SetMemory(m_Ivs.UseData(), 0, m_Ivs.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::GetIv ++---------------------------------------------------------------------*/ +const AP4_UI08* +AP4_PiffSampleEncryptionAtom::GetIv(AP4_Ordinal indx) +{ + if (m_IvSize == 0) return NULL; + unsigned int offset = indx*m_IvSize; + if (offset+m_IvSize > m_Ivs.GetDataSize()) return NULL; + return m_Ivs.GetData()+offset; +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::SetIv ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffSampleEncryptionAtom::SetIv(AP4_Ordinal indx, const AP4_UI08* iv) +{ + if (m_IvSize == 0) return AP4_ERROR_INVALID_STATE; + if (indx >= m_IvCount) { + return AP4_ERROR_OUT_OF_RANGE; + } + AP4_CopyMemory(m_Ivs.UseData()+indx*m_IvSize, iv, m_IvSize); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffSampleEncryptionAtom::InspectFields(AP4_AtomInspector& inspector) +{ + if (m_Flags & AP4_PIFF_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) { + inspector.AddField("AlgorithmID", m_AlgorithmId); + inspector.AddField("IV_size", m_IvSize); + inspector.AddField("KID", m_Kid, 16); + } + + if (m_IvSize > 0 && m_IvSize <= 16 && inspector.GetVerbosity() >= 1) { + unsigned int sample_count = m_Ivs.GetDataSize()/m_IvSize; + for (unsigned int i=0; i<sample_count; i++) { + char header[32]; + char hex[33]; + hex[32] = '\0'; + AP4_FormatString(header, sizeof(header), "IV %4d", i); + AP4_FormatHex(m_Ivs.GetData()+i*m_IvSize, m_IvSize, hex); + inspector.AddField(header, hex); + } + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_PiffSampleEncryptionAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // optional fields + if (m_Flags & AP4_PIFF_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS) { + result = stream.WriteUI24(m_AlgorithmId); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI08(m_IvSize); + if (AP4_FAILED(result)) return result; + result = stream.Write(m_Kid, 16); + if (AP4_FAILED(result)) return result; + } + + // IVs + result = stream.WriteUI32(m_IvCount); + if (AP4_FAILED(result)) return result; + if (m_Ivs.GetDataSize()) { + stream.Write(m_Ivs.GetData(), m_Ivs.GetDataSize()); + if (AP4_FAILED(result)) return result; + } + + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Piff.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Piff.h new file mode 100644 index 000000000..73ad5659c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Piff.h @@ -0,0 +1,430 @@ +/***************************************************************** +| +| AP4 - PIFF support +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_PIFF_H_ +#define _AP4_PIFF_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4SampleEntry.h" +#include "Ap4Atom.h" +#include "Ap4AtomFactory.h" +#include "Ap4SampleDescription.h" +#include "Ap4Processor.h" +#include "Ap4Protection.h" +#include "Ap4UuidAtom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_StreamCipher; +class AP4_CbcStreamCipher; +class AP4_CtrStreamCipher; +class AP4_PiffSampleEncryptionAtom; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_PIFF = AP4_ATOM_TYPE('p','i','f','f'); +const AP4_UI32 AP4_PROTECTION_SCHEME_VERSION_PIFF_10 = 0x00010000; +const AP4_UI32 AP4_PIFF_BRAND = AP4_ATOM_TYPE('p','i','f','f'); +const AP4_UI32 AP4_PIFF_ALGORITHM_ID_NONE = 0; +const AP4_UI32 AP4_PIFF_ALGORITHM_ID_CTR = 1; +const AP4_UI32 AP4_PIFF_ALGORITHM_ID_CBC = 2; + +extern AP4_UI08 const AP4_UUID_PIFF_TRACK_ENCRYPTION_ATOM[16]; +extern AP4_UI08 const AP4_UUID_PIFF_SAMPLE_ENCRYPTION_ATOM[16]; + +const unsigned int AP4_PIFF_SAMPLE_ENCRYPTION_FLAG_OVERRIDE_TRACK_ENCRYPTION_DEFAULTS = 1; + +typedef enum { + AP4_PIFF_CIPHER_MODE_CTR, + AP4_PIFF_CIPHER_MODE_CBC +} AP4_PiffCipherMode; + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncrypter ++---------------------------------------------------------------------*/ +class AP4_PiffSampleEncrypter +{ +public: + // constructor and destructor + AP4_PiffSampleEncrypter() { AP4_SetMemory(m_Iv, 0, 16); }; + virtual ~AP4_PiffSampleEncrypter() {} + + // methods + virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out) = 0; + + void SetIv(const AP4_UI08* iv) { AP4_CopyMemory(m_Iv, iv, 16); } + const AP4_UI08* GetIv() { return m_Iv; } + +protected: + AP4_UI08 m_Iv[16]; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleEncrypter ++---------------------------------------------------------------------*/ +class AP4_PiffCtrSampleEncrypter : public AP4_PiffSampleEncrypter +{ +public: + // constructor and destructor + AP4_PiffCtrSampleEncrypter(AP4_BlockCipher* block_cipher); + ~AP4_PiffCtrSampleEncrypter(); + + // methods + virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out); + +protected: + // members + AP4_CtrStreamCipher* m_Cipher; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCtrSampleEncrypter ++---------------------------------------------------------------------*/ +class AP4_PiffAvcCtrSampleEncrypter : public AP4_PiffCtrSampleEncrypter +{ +public: + // constructor and destructor + AP4_PiffAvcCtrSampleEncrypter(AP4_BlockCipher* block_cipher, + AP4_Size nalu_length_size) : + AP4_PiffCtrSampleEncrypter(block_cipher), + m_NaluLengthSize(nalu_length_size) {} + + // methods + virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out); + +private: + // members + AP4_Size m_NaluLengthSize; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleEncrypter ++---------------------------------------------------------------------*/ +class AP4_PiffCbcSampleEncrypter : public AP4_PiffSampleEncrypter +{ +public: + // constructor and destructor + AP4_PiffCbcSampleEncrypter(AP4_BlockCipher* block_cipher); + ~AP4_PiffCbcSampleEncrypter(); + + // methods + virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out); + +protected: + // members + AP4_CbcStreamCipher* m_Cipher; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCbcSampleEncrypter ++---------------------------------------------------------------------*/ +class AP4_PiffAvcCbcSampleEncrypter : public AP4_PiffCbcSampleEncrypter +{ +public: + // constructor and destructor + AP4_PiffAvcCbcSampleEncrypter(AP4_BlockCipher* block_cipher, + AP4_Size nalu_length_size) : + AP4_PiffCbcSampleEncrypter(block_cipher), + m_NaluLengthSize(nalu_length_size) {} + + // methods + virtual AP4_Result EncryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out); + +private: + // members + AP4_Size m_NaluLengthSize; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffEncryptingProcessor ++---------------------------------------------------------------------*/ +class AP4_PiffEncryptingProcessor : public AP4_Processor +{ +public: + // types + struct Encrypter { + Encrypter(AP4_UI32 track_id, AP4_PiffSampleEncrypter* sample_encrypter) : + m_TrackId(track_id), + m_SampleEncrypter(sample_encrypter) {} + Encrypter() { delete m_SampleEncrypter; } + AP4_UI32 m_TrackId; + AP4_PiffSampleEncrypter* m_SampleEncrypter; + }; + + // constructor + AP4_PiffEncryptingProcessor(AP4_PiffCipherMode cipher_mode, + AP4_BlockCipherFactory* block_cipher_factory = NULL); + ~AP4_PiffEncryptingProcessor(); + + // accessors + AP4_ProtectionKeyMap& GetKeyMap() { return m_KeyMap; } + AP4_TrackPropertyMap& GetPropertyMap() { return m_PropertyMap; } + + // AP4_Processor methods + virtual AP4_Result Initialize(AP4_AtomParent& top_level, + AP4_ByteStream& stream, + AP4_Processor::ProgressListener* listener = NULL); + virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak); + virtual AP4_Processor::FragmentHandler* CreateFragmentHandler(AP4_ContainerAtom* traf); + +protected: + // members + AP4_PiffCipherMode m_CipherMode; + AP4_BlockCipherFactory* m_BlockCipherFactory; + AP4_ProtectionKeyMap m_KeyMap; + AP4_TrackPropertyMap m_PropertyMap; + AP4_List<Encrypter> m_Encrypters; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffSampleDecrypter ++---------------------------------------------------------------------*/ +class AP4_PiffSampleDecrypter : public AP4_SampleDecrypter +{ +public: + // factory + static AP4_Result Create(AP4_ProtectedSampleDescription* sample_description, + AP4_ContainerAtom* traf, + const AP4_UI08* key, + AP4_Size key_size, + AP4_BlockCipherFactory* block_cipher_factory, + AP4_PiffSampleDecrypter*& decrypter); + + // methods + virtual AP4_Result SetSampleIndex(AP4_Ordinal sample_index); + +protected: + AP4_PiffSampleDecrypter(AP4_PiffSampleEncryptionAtom* sample_encryption_atom) : + m_SampleEncryptionAtom(sample_encryption_atom), + m_SampleIndex(0) {} + AP4_PiffSampleEncryptionAtom* m_SampleEncryptionAtom; + AP4_Ordinal m_SampleIndex; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffNullSampleDecrypter ++---------------------------------------------------------------------*/ +class AP4_PiffNullSampleDecrypter : public AP4_PiffSampleDecrypter +{ +public: + // constructor + AP4_PiffNullSampleDecrypter() : AP4_PiffSampleDecrypter(NULL) {} + + // methods + virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + const AP4_UI08* /*iv = NULL*/) { + data_out.SetData(data_in.GetData(), data_in.GetDataSize()); + return AP4_SUCCESS; + } +}; + +/*---------------------------------------------------------------------- +| AP4_PiffCtrSampleDecrypter ++---------------------------------------------------------------------*/ +class AP4_PiffCtrSampleDecrypter : public AP4_PiffSampleDecrypter +{ +public: + // constructor and destructor + AP4_PiffCtrSampleDecrypter(AP4_BlockCipher* block_cipher, + AP4_Size iv_size, + AP4_PiffSampleEncryptionAtom* sample_encryption_atom); + ~AP4_PiffCtrSampleDecrypter(); + + // methods + virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + const AP4_UI08* iv = NULL); + +private: + // members + AP4_CtrStreamCipher* m_Cipher; + AP4_Size m_IvSize; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCtrSampleDecrypter ++---------------------------------------------------------------------*/ +class AP4_PiffAvcCtrSampleDecrypter : public AP4_PiffCtrSampleDecrypter +{ +public: + // constructor and destructor + AP4_PiffAvcCtrSampleDecrypter(AP4_BlockCipher* block_cipher, + AP4_Size iv_size, + AP4_PiffSampleEncryptionAtom* sample_encryption_atom, + AP4_Size nalu_length_size) : + AP4_PiffCtrSampleDecrypter(block_cipher, iv_size, sample_encryption_atom), + m_NaluLengthSize(nalu_length_size) {} + + // methods + virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + const AP4_UI08* iv = NULL); + +private: + // members + AP4_Size m_NaluLengthSize; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffCbcSampleDecrypter ++---------------------------------------------------------------------*/ +class AP4_PiffCbcSampleDecrypter : public AP4_PiffSampleDecrypter +{ +public: + // constructor and destructor + AP4_PiffCbcSampleDecrypter(AP4_BlockCipher* block_cipher, + AP4_PiffSampleEncryptionAtom* sample_encryption_atom); + ~AP4_PiffCbcSampleDecrypter(); + + // methods + virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + const AP4_UI08* iv = NULL); + +protected: + // members + AP4_CbcStreamCipher* m_Cipher; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffAvcCbcSampleDecrypter ++---------------------------------------------------------------------*/ +class AP4_PiffAvcCbcSampleDecrypter : public AP4_PiffCbcSampleDecrypter +{ +public: + // constructor and destructor + AP4_PiffAvcCbcSampleDecrypter(AP4_BlockCipher* block_cipher, + AP4_PiffSampleEncryptionAtom* sample_encryption_atom, + AP4_Size nalu_length_size) : + AP4_PiffCbcSampleDecrypter(block_cipher, sample_encryption_atom), + m_NaluLengthSize(nalu_length_size) {} + + // methods + virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in, + AP4_DataBuffer& data_out, + const AP4_UI08* iv = NULL); + +private: + // members + AP4_Size m_NaluLengthSize; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffTrackEncryptionAtom ++---------------------------------------------------------------------*/ +class AP4_PiffTrackEncryptionAtom : public AP4_UuidAtom +{ +public: + // class methods + static AP4_PiffTrackEncryptionAtom* Create(AP4_Size size, + AP4_ByteStream& stream); + + // constructors + AP4_PiffTrackEncryptionAtom(AP4_UI32 default_algorithm_id, + AP4_UI08 default_iv_size, + const AP4_UI08* default_kid); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetDefaultAlgorithmId() { return m_DefaultAlgorithmId; } + AP4_UI08 GetDefaultIvSize() { return m_DefaultIvSize; } + const AP4_UI08* GetDefaultKid() { return m_DefaultKid; } + +private: + // methods + AP4_PiffTrackEncryptionAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI32 m_DefaultAlgorithmId; + AP4_UI08 m_DefaultIvSize; + AP4_UI08 m_DefaultKid[16]; +}; + +/*---------------------------------------------------------------------- +| AP4_PiffSampleEncryptionAtom ++---------------------------------------------------------------------*/ +class AP4_PiffSampleEncryptionAtom : public AP4_UuidAtom +{ +public: + // class methods + static AP4_PiffSampleEncryptionAtom* Create(AP4_Size size, + AP4_ByteStream& stream); + + // constructors + AP4_PiffSampleEncryptionAtom(AP4_Cardinal sample_count); + AP4_PiffSampleEncryptionAtom(AP4_UI32 algorithm_id, + AP4_UI08 iv_size, + const AP4_UI08* kid, + AP4_Cardinal sample_count); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetAlgorithmId() { return m_AlgorithmId; } + AP4_UI08 GetIvSize() { return m_IvSize; } + AP4_Result SetIvSize(AP4_UI08 iv_size); + const AP4_UI08* GetKid() { return m_Kid; } + AP4_Cardinal GetIvCount() { return m_IvCount; } + const AP4_UI08* GetIv(AP4_Ordinal indx); + AP4_Result SetIv(AP4_Ordinal indx, const AP4_UI08* iv); + +private: + // methods + AP4_PiffSampleEncryptionAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI32 m_AlgorithmId; + AP4_UI08 m_IvSize; + AP4_UI08 m_Kid[16]; + AP4_Cardinal m_IvCount; + AP4_DataBuffer m_Ivs; +}; + +#endif // _AP4_PIFF_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Processor.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Processor.cpp new file mode 100644 index 000000000..129989b1e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Processor.cpp @@ -0,0 +1,498 @@ +/*****************************************************************
+|
+| AP4 - File Processor
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Processor.h"
+#include "Ap4AtomSampleTable.h"
+#include "Ap4MovieFragment.h"
+#include "Ap4FragmentSampleTable.h"
+#include "Ap4TfhdAtom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4Movie.h"
+#include "Ap4Array.h"
+#include "Ap4Sample.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4TfraAtom.h"
+#include "Ap4DataBuffer.h"
+#include "Ap4Debug.h"
+
+/*----------------------------------------------------------------------
+| types
++---------------------------------------------------------------------*/
+struct AP4_SampleLocator {
+ AP4_SampleLocator() :
+ m_TrakIndex(0),
+ m_SampleTable(NULL),
+ m_SampleIndex(0),
+ m_ChunkIndex(0) {}
+ AP4_Ordinal m_TrakIndex;
+ AP4_AtomSampleTable* m_SampleTable;
+ AP4_Ordinal m_SampleIndex;
+ AP4_Ordinal m_ChunkIndex;
+ AP4_Sample m_Sample;
+};
+
+struct AP4_SampleCursor {
+ AP4_SampleCursor() : m_EndReached(false) {}
+ AP4_SampleLocator m_Locator;
+ bool m_EndReached;
+};
+
+struct AP4_MoofLocator {
+ AP4_MoofLocator(AP4_ContainerAtom* moof, AP4_UI64 offset) :
+ m_Moof(moof),
+ m_Offset(offset) {}
+ AP4_ContainerAtom* m_Moof;
+ AP4_UI64 m_Offset;
+};
+
+/*----------------------------------------------------------------------
+| AP4_Processor::ProcessFragments
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_Processor::ProcessFragments(AP4_MoovAtom* moov,
+ AP4_List<AP4_MoofLocator>& moofs,
+ AP4_ContainerAtom* mfra,
+ AP4_ByteStream& input,
+ AP4_ByteStream& output)
+{
+ // FIXME: this only works for non-changing moofs
+
+ for (AP4_List<AP4_MoofLocator>::Item* item = moofs.FirstItem();
+ item;
+ item = item->GetNext()) {
+ AP4_MoofLocator* locator = item->GetData();
+ AP4_ContainerAtom* moof = locator->m_Moof;
+ AP4_UI64 moof_offset = locator->m_Offset;
+ AP4_UI64 mdat_payload_offset = moof_offset+moof->GetSize()+8;
+ AP4_MovieFragment* fragment = new AP4_MovieFragment(moof);
+ AP4_Sample sample;
+ AP4_DataBuffer sample_data_in;
+ AP4_DataBuffer sample_data_out;
+ AP4_Result result;
+
+ // process all the traf atoms
+ AP4_Array<AP4_Processor::FragmentHandler*> handlers;
+ for (;AP4_Atom* atom = moof->GetChild(AP4_ATOM_TYPE_TRAF, handlers.ItemCount());) {
+ AP4_ContainerAtom* traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
+ AP4_Processor::FragmentHandler* handler = CreateFragmentHandler(traf);
+ if (handler) result = handler->ProcessFragment();
+ handlers.Append(handler);
+ }
+
+ // write the moof
+ AP4_UI64 moof_out_start = 0;
+ output.Tell(moof_out_start);
+ bool moof_has_changed = false;
+ moof->Write(output);
+
+ // process all track runs
+ for (unsigned int i=0; i<handlers.ItemCount(); i++) {
+ AP4_FragmentSampleTable* sample_table = NULL;
+ AP4_Processor::FragmentHandler* handler = handlers[i];
+
+ // get the track ID
+ AP4_ContainerAtom* traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof->GetChild(AP4_ATOM_TYPE_TRAF, i));
+ AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD, i));
+
+ // create a sample table object so we can read the sample data
+ result = fragment->CreateSampleTable(moov, tfhd->GetTrackId(), &input, moof_offset, mdat_payload_offset, sample_table);
+ if (AP4_FAILED(result)) return result;
+
+ // compute the mdat size
+ AP4_UI64 mdat_size = 0;
+ for (unsigned int j=0; j<sample_table->GetSampleCount(); j++) {
+ result = sample_table->GetSample(j, sample);
+ if (AP4_FAILED(result)) return result;
+ mdat_size += sample.GetSize();
+ }
+
+ // write an mdat header
+ if (mdat_size > 0xFFFFFFFF-8) {
+ // we don't support large mdat fragments
+ return AP4_ERROR_OUT_OF_RANGE;
+ }
+ if (mdat_size) {
+ output.WriteUI32((AP4_UI32)(8+mdat_size));
+ output.WriteUI32(AP4_ATOM_TYPE_MDAT);
+ }
+
+#if defined(AP4_DEBUG)
+ AP4_Position before;
+ output.Tell(before);
+#endif
+
+ // write the mdat
+ for (unsigned int j=0; j<sample_table->GetSampleCount(); j++) {
+ result = sample_table->GetSample(j, sample);
+ if (AP4_FAILED(result)) return result;
+ sample.ReadData(sample_data_in);
+
+ // process the sample data
+ if (handler) {
+ result = handler->ProcessSample(sample_data_in, sample_data_out);
+ if (AP4_FAILED(result)) return result;
+
+ // write the sample data
+ result = output.Write(sample_data_out.GetData(), sample_data_out.GetDataSize());
+ if (AP4_FAILED(result)) return result;
+
+ // give the handler a chance to update the atoms
+ result = handler->FinishFragment();
+ if (AP4_SUCCEEDED(result)) moof_has_changed = true;
+ } else {
+ // write the sample data (unmodified)
+ result = output.Write(sample_data_in.GetData(), sample_data_in.GetDataSize());
+ if (AP4_FAILED(result)) return result;
+ }
+ }
+
+#if defined(AP4_DEBUG)
+ AP4_Position after;
+ output.Tell(after);
+ AP4_ASSERT(after-before == mdat_size);
+#endif
+ delete sample_table;
+ }
+
+ // update the moof if needed
+ AP4_UI64 mdat_out_end = 0;
+ output.Tell(mdat_out_end);
+ if (moof_has_changed) {
+ output.Seek(moof_out_start);
+ moof->Write(output);
+ output.Seek(mdat_out_end);
+ }
+
+ // update the mfra if we have one
+ if (mfra) {
+ for (AP4_List<AP4_Atom>::Item* mfra_item = mfra->GetChildren().FirstItem();
+ mfra_item;
+ mfra_item = mfra_item->GetNext()) {
+ if (mfra_item->GetData()->GetType() != AP4_ATOM_TYPE_TFRA) continue;
+ AP4_TfraAtom* tfra = AP4_DYNAMIC_CAST(AP4_TfraAtom, mfra_item->GetData());
+ if (tfra == NULL) continue;
+ AP4_Array<AP4_TfraAtom::Entry>& entries = tfra->GetEntries();
+ AP4_Cardinal entry_count = entries.ItemCount();
+ for (unsigned int i=0; i<entry_count; i++) {
+ if (entries[i].m_MoofOffset == locator->m_Offset) {
+ entries[i].m_MoofOffset = moof_out_start;
+ }
+ }
+ }
+ }
+
+ delete fragment;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Processor::Process
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_Processor::Process(AP4_ByteStream& input,
+ AP4_ByteStream& output,
+ ProgressListener* listener,
+ AP4_AtomFactory& atom_factory)
+{
+ // read all atoms.
+ // keep all atoms except [mdat]
+ // keep a ref to [moov]
+ // put [moof] atoms in a separate list
+ AP4_AtomParent top_level;
+ AP4_MoovAtom* moov = NULL;
+ AP4_ContainerAtom* mfra = NULL;
+ AP4_List<AP4_MoofLocator> moofs;
+ AP4_UI64 stream_offset = 0;
+ for (AP4_Atom* atom = NULL;
+ AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(input, atom));
+ input.Tell(stream_offset)) {
+ if (atom->GetType() == AP4_ATOM_TYPE_MDAT) {
+ continue;
+ } else if (atom->GetType() == AP4_ATOM_TYPE_MOOV) {
+ moov = (AP4_MoovAtom*)atom;
+ } else if (atom->GetType() == AP4_ATOM_TYPE_MOOF) {
+ AP4_ContainerAtom* moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
+ if (moof) {
+ moofs.Add(new AP4_MoofLocator(moof, stream_offset));
+ }
+ continue;
+ } else if (atom->GetType() == AP4_ATOM_TYPE_MFRA) {
+ mfra = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
+ continue;
+ }
+ top_level.AddChild(atom);
+ }
+
+ // initialize the processor
+ AP4_Result result = Initialize(top_level, input);
+ if (AP4_FAILED(result)) return result;
+
+ // process the tracks if we have a moov atom
+ AP4_Array<AP4_SampleLocator> locators;
+ AP4_Cardinal track_count = 0;
+ AP4_List<AP4_TrakAtom>* trak_atoms = NULL;
+ AP4_LargeSize mdat_payload_size = 0;
+ TrackHandler** handlers = NULL;
+ AP4_SampleCursor* cursors = NULL;
+ if (moov) {
+ // build an array of track sample locators
+ trak_atoms = &moov->GetTrakAtoms();
+ track_count = trak_atoms->ItemCount();
+ cursors = new AP4_SampleCursor[track_count];
+ handlers = new TrackHandler*[track_count];
+ for (AP4_Ordinal i=0; i<track_count; i++) {
+ handlers[i] = NULL;
+ }
+
+ unsigned int index = 0;
+ for (AP4_List<AP4_TrakAtom>::Item* item = trak_atoms->FirstItem(); item; item=item->GetNext()) {
+ AP4_TrakAtom* trak = item->GetData();
+
+ // find the stsd atom
+ AP4_ContainerAtom* stbl = AP4_DYNAMIC_CAST(AP4_ContainerAtom, trak->FindChild("mdia/minf/stbl"));
+ if (stbl == NULL) continue;
+
+ // see if there's an external data source for this track
+ AP4_ByteStream* trak_data_stream = &input;
+ for (AP4_List<ExternalTrackData>::Item* ditem = m_ExternalTrackData.FirstItem(); ditem; ditem=ditem->GetNext()) {
+ ExternalTrackData* tdata = ditem->GetData();
+ if (tdata->m_TrackId == trak->GetId()) {
+ trak_data_stream = tdata->m_MediaData;
+ break;
+ }
+ }
+
+ // create the track handler
+ handlers[index] = CreateTrackHandler(trak);
+ cursors[index].m_Locator.m_TrakIndex = index;
+ cursors[index].m_Locator.m_SampleTable = new AP4_AtomSampleTable(stbl, *trak_data_stream);
+ cursors[index].m_Locator.m_SampleIndex = 0;
+ cursors[index].m_Locator.m_ChunkIndex = 0;
+ if (cursors[index].m_Locator.m_SampleTable->GetSampleCount()) {
+ cursors[index].m_Locator.m_SampleTable->GetSample(0, cursors[index].m_Locator.m_Sample);
+ } else {
+ cursors[index].m_EndReached = true;
+ }
+
+ index++;
+ }
+
+ // figure out the layout of the chunks
+ for (;;) {
+ // see which is the next sample to write
+ AP4_UI64 min_offset = (AP4_UI64)(-1);
+ int cursor = -1;
+ for (unsigned int i=0; i<track_count; i++) {
+ if (!cursors[i].m_EndReached &&
+ cursors[i].m_Locator.m_Sample.GetOffset() <= min_offset) {
+ min_offset = cursors[i].m_Locator.m_Sample.GetOffset();
+ cursor = i;
+ }
+ }
+
+ // stop if all cursors are exhausted
+ if (cursor == -1) break;
+
+ // append this locator to the layout list
+ AP4_SampleLocator& locator = cursors[cursor].m_Locator;
+ locators.Append(locator);
+
+ // move the cursor to the next sample
+ locator.m_SampleIndex++;
+ if (locator.m_SampleIndex == locator.m_SampleTable->GetSampleCount()) {
+ // mark this track as completed
+ cursors[cursor].m_EndReached = true;
+ } else {
+ // get the next sample info
+ locator.m_SampleTable->GetSample(locator.m_SampleIndex, locator.m_Sample);
+ AP4_Ordinal skip, sdesc;
+ locator.m_SampleTable->GetChunkForSample(locator.m_SampleIndex,
+ locator.m_ChunkIndex,
+ skip, sdesc);
+ }
+ }
+
+ // update the stbl atoms and compute the mdat size
+ int current_track = -1;
+ int current_chunk = -1;
+ AP4_Position current_chunk_offset = 0;
+ AP4_Size current_chunk_size = 0;
+ for (AP4_Ordinal i=0; i<locators.ItemCount(); i++) {
+ AP4_SampleLocator& locator = locators[i];
+ if ((int)locator.m_TrakIndex != current_track ||
+ (int)locator.m_ChunkIndex != current_chunk) {
+ // start a new chunk for this track
+ current_chunk_offset += current_chunk_size;
+ current_chunk_size = 0;
+ current_track = locator.m_TrakIndex;
+ current_chunk = locator.m_ChunkIndex;
+ locator.m_SampleTable->SetChunkOffset(locator.m_ChunkIndex, current_chunk_offset);
+ }
+ AP4_Size sample_size;
+ TrackHandler* handler = handlers[locator.m_TrakIndex];
+ if (handler) {
+ sample_size = handler->GetProcessedSampleSize(locator.m_Sample);
+ locator.m_SampleTable->SetSampleSize(locator.m_SampleIndex, sample_size);
+ } else {
+ sample_size = locator.m_Sample.GetSize();
+ }
+ current_chunk_size += sample_size;
+ mdat_payload_size += sample_size;
+ }
+
+ // process the tracks (ex: sample descriptions processing)
+ for (AP4_Ordinal i=0; i<track_count; i++) {
+ TrackHandler* handler = handlers[i];
+ if (handler) handler->ProcessTrack();
+ }
+ }
+
+ // finalize the processor
+ Finalize(top_level);
+
+ // calculate the size of all atoms combined
+ AP4_UI64 atoms_size = 0;
+ top_level.GetChildren().Apply(AP4_AtomSizeAdder(atoms_size));
+
+ // see if we need a 64-bit or 32-bit mdat
+ AP4_Size mdat_header_size = AP4_ATOM_HEADER_SIZE;
+ if (mdat_payload_size+mdat_header_size > 0xFFFFFFFF) {
+ // we need a 64-bit size
+ mdat_header_size += 8;
+ }
+
+ // adjust the chunk offsets
+ for (AP4_Ordinal i=0; i<track_count; i++) {
+ AP4_TrakAtom* trak;
+ trak_atoms->Get(i, trak);
+ trak->AdjustChunkOffsets(atoms_size+mdat_header_size);
+ }
+
+ // write all atoms
+ top_level.GetChildren().Apply(AP4_AtomListWriter(output));
+
+ // write mdat header
+ if (mdat_payload_size) {
+ if (mdat_header_size == AP4_ATOM_HEADER_SIZE) {
+ // 32-bit size
+ output.WriteUI32((AP4_UI32)(mdat_header_size+mdat_payload_size));
+ output.WriteUI32(AP4_ATOM_TYPE_MDAT);
+ } else {
+ // 64-bit size
+ output.WriteUI32(1);
+ output.WriteUI32(AP4_ATOM_TYPE_MDAT);
+ output.WriteUI64(mdat_header_size+mdat_payload_size);
+ }
+ }
+
+#if defined(AP4_DEBUG)
+ AP4_Position before;
+ output.Tell(before);
+#endif
+
+ // write the samples
+ if (moov) {
+ AP4_Sample sample;
+ AP4_DataBuffer data_in;
+ AP4_DataBuffer data_out;
+ for (unsigned int i=0; i<locators.ItemCount(); i++) {
+ AP4_SampleLocator& locator = locators[i];
+ locator.m_Sample.ReadData(data_in);
+ TrackHandler* handler = handlers[locator.m_TrakIndex];
+ if (handler) {
+ result = handler->ProcessSample(data_in, data_out);
+ if (AP4_FAILED(result)) return result;
+ output.Write(data_out.GetData(), data_out.GetDataSize());
+ } else {
+ output.Write(data_in.GetData(), data_in.GetDataSize());
+ }
+
+ // notify the progress listener
+ if (listener) {
+ listener->OnProgress(i+1, locators.ItemCount());
+ }
+ }
+
+ // cleanup
+ for (AP4_Ordinal i=0; i<track_count; i++) {
+ delete cursors[i].m_Locator.m_SampleTable;
+ delete handlers[i];
+ }
+ delete[] cursors;
+ delete[] handlers;
+ }
+
+#if defined(AP4_DEBUG)
+ AP4_Position after;
+ output.Tell(after);
+ AP4_ASSERT(after-before == mdat_payload_size);
+#endif
+
+ // process the fragments, if any
+ result = ProcessFragments(moov, moofs, mfra, input, output);
+ if (AP4_FAILED(result)) return result;
+
+ // write the mfra atom at the end if we have one
+ if (mfra) {
+ mfra->Write(output);
+ }
+
+ // cleanup
+ moofs.DeleteReferences();
+ delete mfra;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Processor:Initialize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_Processor::Initialize(AP4_AtomParent& /* top_level */,
+ AP4_ByteStream& /* stream */,
+ ProgressListener* /* listener */)
+{
+ // default implementation: do nothing
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_Processor:Finalize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_Processor::Finalize(AP4_AtomParent& /* top_level */,
+ ProgressListener* /* listener */ )
+{
+ // default implementation: do nothing
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Processor.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Processor.h new file mode 100644 index 000000000..2e7b4186d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Processor.h @@ -0,0 +1,237 @@ +/*****************************************************************
+|
+| AP4 - File Processor
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+#ifndef _AP4_PROCESSOR_H_
+#define _AP4_PROCESSOR_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4File.h"
+#include "Ap4Track.h"
+#include "Ap4Sample.h"
+
+/*----------------------------------------------------------------------
+| class references
++---------------------------------------------------------------------*/
+class AP4_ContainerAtom;
+class AP4_ByteStream;
+class AP4_DataBuffer;
+class AP4_TrakAtom;
+struct AP4_MoofLocator;
+
+/*----------------------------------------------------------------------
+| AP4_Processor
++---------------------------------------------------------------------*/
+class AP4_Processor {
+public:
+ /**
+ * Abstract class that defines the interface implemented by progress
+ * listeners. A progress listener is called during the AP4_Processor::Process()
+ * method to notify of progres information.
+ */
+ class ProgressListener {
+ public:
+ virtual ~ProgressListener() {}
+
+ /**
+ * This method is called during the call to AP4_Processor::Process() to
+ * notify of the progress of the operation. If this method returns an
+ * error result, processing is aborted.
+ * @param step Ordinal of the current progress step.
+ * @param total Total number of steps.
+ * @return A result code. If this method returns AP4_SUCCESS, the
+ * processing continues. If an error code is returned, the processing
+ * is aborted.
+ */
+ virtual AP4_Result OnProgress(unsigned int step,
+ unsigned int total) = 0;
+ };
+
+ /**
+ * Abstract class that defines the interface implemented by concrete
+ * track handlers. A track handler is responsible for processing a
+ * track and its media samples.
+ */
+ class TrackHandler {
+ public:
+ /**
+ * Default destructor.
+ */
+ virtual ~TrackHandler() {}
+
+ /**
+ * A track handler may override this method if it needs to modify
+ * the track atoms before processing the track samples.
+ */
+ virtual AP4_Result ProcessTrack() { return AP4_SUCCESS; }
+
+ /**
+ * Returns the size of a sample after processing.
+ * @param sample Sample of which the processed size is requested.
+ * @return Size of the sample data after processing.
+ */
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample) { return sample.GetSize(); }
+
+ /**
+ * Process the data of one sample.
+ * @param data_in Data buffer with the data of the sample to process.
+ * @param data_out Data buffer in which the processed sample data is
+ * returned.
+ */
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out) = 0;
+ };
+
+ /**
+ * Abstract class that defines the interface implemented by concrete
+ * fragment handlers. A fragment handler is responsible for processing a
+ * fragment and its media samples.
+ */
+ class FragmentHandler {
+ public:
+ /**
+ * Default destructor.
+ */
+ virtual ~FragmentHandler() {}
+
+ /**
+ * A fragment handler may override this method if it needs to modify
+ * the fragment atoms before processing the fragment samples.
+ */
+ virtual AP4_Result ProcessFragment() { return AP4_SUCCESS; }
+
+ /**
+ * A fragment handler may override this method if it needs to modify
+ * the fragment atoms after processing the fragment samples.
+ * NOTE: this method MUST NOT change the size of any of the atoms.
+ */
+ virtual AP4_Result FinishFragment() { return AP4_ERROR_NOT_SUPPORTED; }
+
+ /**
+ * Returns the size of a sample after processing.
+ * @param sample Sample of which the processed size is requested.
+ * @return Size of the sample data after processing.
+ */
+ virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample) { return sample.GetSize(); }
+
+ /**
+ * Process the data of one sample.
+ * @param data_in Data buffer with the data of the sample to process.
+ * @param data_out Data buffer in which the processed sample data is
+ * returned.
+ */
+ virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out) = 0;
+ };
+
+ /**
+ * Default destructor
+ */
+ virtual ~AP4_Processor() { m_ExternalTrackData.DeleteReferences(); }
+
+ /**
+ * Process the input stream into an output stream.
+ * @param input Reference to the file to process.
+ * @param output Output stream to which the processed input
+ * will be written.
+ * @param listener Pointer to a listener, or NULL. The listener
+ * will be called one or more times before this method returns,
+ * with progress information.
+ */
+ AP4_Result Process(AP4_ByteStream& input,
+ AP4_ByteStream& output,
+ ProgressListener* listener = NULL,
+ AP4_AtomFactory& atom_factory =
+ AP4_DefaultAtomFactory::Instance);
+
+ /**
+ * This method can be overridden by concrete subclasses.
+ * It is called just after the input stream has been parsed into
+ * an atom tree, before the processing of the tracks.
+ * @param top_level Container atom containing all the atoms parsed
+ * from the input stream. Note that this atom does not actually
+ * exist in the file; it is a synthetised container created for the
+ * purpose of holding together all the input's top-level atoms.
+ */
+ virtual AP4_Result Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ ProgressListener* listener = NULL);
+
+ /**
+ * This method can be overridden by concrete subclasses.
+ * It is called just after the tracks have been processed.
+ */
+ virtual AP4_Result Finalize(AP4_AtomParent& top_level,
+ ProgressListener* listener = NULL);
+
+ /**
+ * This method can be overridden by concrete subclasses.
+ * It is called once for each track in the input file.
+ * @param track Pointer to the track for which a handler should be
+ * created.
+ * @return A pointer to a track handler, or NULL if no handler
+ * needs to be created for that track.
+ */
+ virtual TrackHandler* CreateTrackHandler(AP4_TrakAtom* /*trak*/) { return NULL; }
+
+ /**
+ * This method can be overridden by concrete subclasses.
+ * It is called once for each fragment in the input file.
+ * @param track Pointer to the fragment for which a handler should be
+ * created.
+ * @return A pointer to a fragment handler, or NULL if no handler
+ * needs to be created for that fragment.
+ */
+ virtual FragmentHandler* CreateFragmentHandler(AP4_ContainerAtom* /*traf*/) { return NULL; }
+
+protected:
+ class ExternalTrackData {
+ public:
+ ExternalTrackData(unsigned int track_id, AP4_ByteStream* media_data) :
+ m_TrackId(track_id), m_MediaData(media_data) {
+ media_data->AddReference();
+ }
+ ~ExternalTrackData() { m_MediaData->Release(); }
+ unsigned int m_TrackId;
+ AP4_ByteStream* m_MediaData;
+ };
+
+ AP4_Result ProcessFragments(AP4_MoovAtom* moov,
+ AP4_List<AP4_MoofLocator>& moofs,
+ AP4_ContainerAtom* mfra,
+ AP4_ByteStream& input,
+ AP4_ByteStream& output);
+
+
+ AP4_List<ExternalTrackData> m_ExternalTrackData;
+};
+
+#endif // _AP4_PROCESSOR_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Protection.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Protection.cpp new file mode 100644 index 000000000..cf918b3f9 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Protection.cpp @@ -0,0 +1,1335 @@ +/*****************************************************************
+|
+| AP4 - Protected Stream Support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Protection.h"
+#include "Ap4SchmAtom.h"
+#include "Ap4StsdAtom.h"
+#include "Ap4FtypAtom.h"
+#include "Ap4Sample.h"
+#include "Ap4StreamCipher.h"
+#include "Ap4IsfmAtom.h"
+#include "Ap4FrmaAtom.h"
+#include "Ap4IkmsAtom.h"
+#include "Ap4IsfmAtom.h"
+#include "Ap4IsltAtom.h"
+#include "Ap4Utils.h"
+#include "Ap4TrakAtom.h"
+#include "Ap4IsmaCryp.h"
+#include "Ap4AesBlockCipher.h"
+#include "Ap4OmaDcf.h"
+#include "Ap4Marlin.h"
+#include "Ap4Piff.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_ProtectedSampleDescription)
+
+/*----------------------------------------------------------------------
+| AP4_EncaSampleEntry::AP4_EncaSampleEntry
++---------------------------------------------------------------------*/
+AP4_EncaSampleEntry::AP4_EncaSampleEntry(AP4_UI32 type,
+ AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_AudioSampleEntry(type, size, stream, atom_factory)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncaSampleEntry::AP4_EncaSampleEntry
++---------------------------------------------------------------------*/
+AP4_EncaSampleEntry::AP4_EncaSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_AudioSampleEntry(AP4_ATOM_TYPE_ENCA, size, stream, atom_factory)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncaSampleEntry::ToSampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_EncaSampleEntry::ToSampleDescription()
+{
+ // get the original sample format
+ AP4_FrmaAtom* frma = (AP4_FrmaAtom*)FindChild("sinf/frma");
+
+ // get the schi atom
+ AP4_ContainerAtom* schi;
+ schi = static_cast<AP4_ContainerAtom*>(FindChild("sinf/schi"));
+
+ // get the scheme info
+ AP4_SchmAtom* schm = (AP4_SchmAtom*)FindChild("sinf/schm");
+ AP4_UI32 original_format = frma?frma->GetOriginalFormat():AP4_ATOM_TYPE_MP4A;
+ if (schm) {
+ // create the original sample description
+ return new AP4_ProtectedSampleDescription(
+ m_Type,
+ ToTargetSampleDescription(original_format),
+ original_format,
+ schm->GetSchemeType(),
+ schm->GetSchemeVersion(),
+ schm->GetSchemeUri().GetChars(),
+ schi);
+ } else if (schi) {
+ // try to see if we can guess the protection scheme from the 'schi' contents
+ AP4_Atom* odkm = schi->GetChild(AP4_ATOM_TYPE_ODKM);
+ if (odkm) {
+ // create the original sample description
+ return new AP4_ProtectedSampleDescription(
+ m_Type,
+ ToTargetSampleDescription(original_format),
+ original_format,
+ AP4_PROTECTION_SCHEME_TYPE_OMA,
+ AP4_PROTECTION_SCHEME_VERSION_OMA_20,
+ NULL,
+ schi);
+ }
+ }
+
+ // unknown scheme
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncaSampleEntry::ToTargetSampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_EncaSampleEntry::ToTargetSampleDescription(AP4_UI32 format)
+{
+ switch (format) {
+ case AP4_ATOM_TYPE_MP4A: {
+ AP4_EsdsAtom* esds = AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS));
+ if (esds == NULL) {
+ // check if this is a quicktime style sample description
+ if (m_QtVersion > 0) {
+ esds = AP4_DYNAMIC_CAST(AP4_EsdsAtom, FindChild("wave/esds"));
+ }
+ }
+ return new AP4_MpegAudioSampleDescription(
+ GetSampleRate(),
+ GetSampleSize(),
+ GetChannelCount(),
+ esds);
+ }
+
+ default:
+ return new AP4_GenericAudioSampleDescription(
+ format,
+ GetSampleRate(),
+ GetSampleSize(),
+ GetChannelCount(),
+ this);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncvSampleEntry::AP4_EncvSampleEntry
++---------------------------------------------------------------------*/
+AP4_EncvSampleEntry::AP4_EncvSampleEntry(AP4_UI32 type,
+ AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_VisualSampleEntry(type, size, stream, atom_factory)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncvSampleEntry::AP4_EncvSampleEntry
++---------------------------------------------------------------------*/
+AP4_EncvSampleEntry::AP4_EncvSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_VisualSampleEntry(AP4_ATOM_TYPE_ENCV, size, stream, atom_factory)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncvSampleEntry::ToSampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_EncvSampleEntry::ToSampleDescription()
+{
+ // get the original sample format
+ AP4_FrmaAtom* frma = (AP4_FrmaAtom*)FindChild("sinf/frma");
+
+ // get the schi atom
+ AP4_ContainerAtom* schi;
+ schi = static_cast<AP4_ContainerAtom*>(FindChild("sinf/schi"));
+
+ // get the scheme info
+ AP4_SchmAtom* schm = (AP4_SchmAtom*)FindChild("sinf/schm");
+ AP4_UI32 original_format = frma?frma->GetOriginalFormat():AP4_ATOM_TYPE_MP4V;
+ if (schm) {
+ // create the sample description
+ return new AP4_ProtectedSampleDescription(
+ m_Type,
+ ToTargetSampleDescription(original_format),
+ original_format,
+ schm->GetSchemeType(),
+ schm->GetSchemeVersion(),
+ schm->GetSchemeUri().GetChars(),
+ schi);
+ } else if (schi) {
+ // try to see if we can guess the protection scheme from the 'schi' contents
+ AP4_Atom* odkm = schi->GetChild(AP4_ATOM_TYPE_ODKM);
+ if (odkm) {
+ // create the original sample description
+ return new AP4_ProtectedSampleDescription(
+ m_Type,
+ ToTargetSampleDescription(original_format),
+ original_format,
+ AP4_PROTECTION_SCHEME_TYPE_OMA,
+ AP4_PROTECTION_SCHEME_VERSION_OMA_20,
+ NULL,
+ schi);
+ }
+ }
+
+ // unknown scheme
+ return NULL;
+
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncvSampleEntry::ToTargetSampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_EncvSampleEntry::ToTargetSampleDescription(AP4_UI32 format)
+{
+ switch (format) {
+ case AP4_ATOM_TYPE_AVC1:
+ return new AP4_AvcSampleDescription(
+ m_Width,
+ m_Height,
+ m_Depth,
+ m_CompressorName.GetChars(),
+ this);
+
+ case AP4_ATOM_TYPE_MP4V:
+ return new AP4_MpegVideoSampleDescription(
+ m_Width,
+ m_Height,
+ m_Depth,
+ m_CompressorName.GetChars(),
+ AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS)));
+
+ default:
+ return new AP4_GenericVideoSampleDescription(
+ format,
+ m_Width,
+ m_Height,
+ m_Depth,
+ m_CompressorName.GetChars(),
+ this);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_DrmsSampleEntry::AP4_DrmsSampleEntry
++---------------------------------------------------------------------*/
+AP4_DrmsSampleEntry::AP4_DrmsSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_EncaSampleEntry(AP4_ATOM_TYPE_DRMS, size, stream, atom_factory)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_DrmiSampleEntry::AP4_DrmiSampleEntry
++---------------------------------------------------------------------*/
+AP4_DrmiSampleEntry::AP4_DrmiSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_EncvSampleEntry(AP4_ATOM_TYPE_DRMI, size, stream, atom_factory)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionSchemeInfo::~AP4_ProtectionSchemeInfo
++---------------------------------------------------------------------*/
+AP4_ProtectionSchemeInfo::~AP4_ProtectionSchemeInfo()
+{
+ delete m_SchiAtom;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionSchemeInfo::AP4_ProtectionSchemeInfo
++---------------------------------------------------------------------*/
+AP4_ProtectionSchemeInfo::AP4_ProtectionSchemeInfo(AP4_ContainerAtom* schi)
+{
+ if (schi) {
+ m_SchiAtom = (AP4_ContainerAtom*)schi->Clone();
+ } else {
+ m_SchiAtom = NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::AP4_ProtectionKeyMap
++---------------------------------------------------------------------*/
+AP4_ProtectionKeyMap::AP4_ProtectionKeyMap()
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::~AP4_ProtectionKeyMap
++---------------------------------------------------------------------*/
+AP4_ProtectionKeyMap::~AP4_ProtectionKeyMap()
+{
+ m_KeyEntries.DeleteReferences();
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::SetKey
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ProtectionKeyMap::SetKey(AP4_UI32 track_id, const AP4_UI08* key, const AP4_UI08* iv)
+{
+ KeyEntry* entry = GetEntry(track_id);
+ if (entry == NULL) {
+ m_KeyEntries.Add(new KeyEntry(track_id, key, iv));
+ } else {
+ entry->SetKey(key, iv);
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::SetKey
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ProtectionKeyMap::SetKeys(const AP4_ProtectionKeyMap& key_map)
+{
+ AP4_List<KeyEntry>::Item* item = key_map.m_KeyEntries.FirstItem();
+ while (item) {
+ KeyEntry* entry = item->GetData();
+ m_KeyEntries.Add(new KeyEntry(entry->m_TrackId,
+ entry->m_Key,
+ entry->m_IV));
+ item = item->GetNext();
+ }
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::GetKeyIv
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ProtectionKeyMap::GetKeyAndIv(AP4_UI32 track_id,
+ const AP4_UI08*& key,
+ const AP4_UI08*& iv)
+{
+ KeyEntry* entry = GetEntry(track_id);
+ if (entry) {
+ key = entry->m_Key;
+ iv = entry->m_IV;
+ return AP4_SUCCESS;
+ } else {
+ return AP4_ERROR_NO_SUCH_ITEM;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::GetKey
++---------------------------------------------------------------------*/
+const AP4_UI08*
+AP4_ProtectionKeyMap::GetKey(AP4_UI32 track_id) const
+{
+ KeyEntry* entry = GetEntry(track_id);
+ if (entry) {
+ return entry->m_Key;
+ } else {
+ return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::GetEntry
++---------------------------------------------------------------------*/
+AP4_ProtectionKeyMap::KeyEntry*
+AP4_ProtectionKeyMap::GetEntry(AP4_UI32 track_id) const
+{
+ AP4_List<KeyEntry>::Item* item = m_KeyEntries.FirstItem();
+ while (item) {
+ KeyEntry* entry = (KeyEntry*)item->GetData();
+ if (entry->m_TrackId == track_id) return entry;
+ item = item->GetNext();
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::KeyEntry::KeyEntry
++---------------------------------------------------------------------*/
+AP4_ProtectionKeyMap::KeyEntry::KeyEntry(AP4_UI32 track_id,
+ const AP4_UI08* key,
+ const AP4_UI08* iv /* = NULL */) :
+ m_TrackId(track_id)
+{
+ SetKey(key, iv);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap::KeyEntry::SetKey
++---------------------------------------------------------------------*/
+void
+AP4_ProtectionKeyMap::KeyEntry::SetKey(const AP4_UI08* key, const AP4_UI08* iv)
+{
+ AP4_CopyMemory(m_Key, key, sizeof(m_Key));
+ if (iv) {
+ AP4_CopyMemory(m_IV, iv, sizeof(m_IV));
+ } else {
+ AP4_SetMemory(m_IV, 0, sizeof(m_IV));
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrackPropertyMap::~AP4_TrackPropertyMap
++---------------------------------------------------------------------*/
+AP4_TrackPropertyMap::~AP4_TrackPropertyMap()
+{
+ m_Entries.DeleteReferences();
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrackPropertyMap::SetProperty
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_TrackPropertyMap::SetProperty(AP4_UI32 track_id,
+ const char* name,
+ const char* value)
+{
+ return m_Entries.Add(new Entry(track_id, name, value));
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrackPropertyMap::SetProperties
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_TrackPropertyMap::SetProperties(const AP4_TrackPropertyMap& properties)
+{
+ AP4_List<Entry>::Item* item = properties.m_Entries.FirstItem();
+ while (item) {
+ Entry* entry = item->GetData();
+ m_Entries.Add(new Entry(entry->m_TrackId,
+ entry->m_Name.GetChars(),
+ entry->m_Value.GetChars()));
+ item = item->GetNext();
+ }
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrackPropertyMap::GetProperty
++---------------------------------------------------------------------*/
+const char*
+AP4_TrackPropertyMap::GetProperty(AP4_UI32 track_id, const char* name)
+{
+ AP4_List<Entry>::Item* item = m_Entries.FirstItem();
+ while (item) {
+ Entry* entry = item->GetData();
+ if (entry->m_TrackId == track_id &&
+ AP4_CompareStrings(entry->m_Name.GetChars(), name) == 0) {
+ return entry->m_Value.GetChars();
+ }
+ item = item->GetNext();
+ }
+
+ // not found
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrackPropertyMap::GetTextualHeaders
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_TrackPropertyMap::GetTextualHeaders(AP4_UI32 track_id, AP4_DataBuffer& textual_headers)
+{
+ AP4_Size buffer_size = 0;
+ AP4_Result result = AP4_SUCCESS;
+ AP4_Byte* data_buffer;
+
+ // get the size needed for the textual headers
+ AP4_List<Entry>::Item* item = m_Entries.FirstItem();
+ while (item) {
+ Entry* entry = item->GetData();
+ if (entry->m_TrackId == track_id) {
+ const char* name = entry->m_Name.GetChars();
+ if (AP4_CompareStrings(name, "ContentId") != 0 &&
+ AP4_CompareStrings(name, "RightsIssuerUrl") != 0 &&
+ AP4_CompareStrings(name, "KID") != 0) {
+ buffer_size += (entry->m_Name.GetLength() +
+ entry->m_Value.GetLength() +
+ 2); // colon + nul
+
+ }
+ }
+ item = item->GetNext();
+ }
+
+ result = textual_headers.SetDataSize(buffer_size);
+ AP4_CHECK(result);
+
+ data_buffer = textual_headers.UseData();
+
+ // set the textual headers
+ item = m_Entries.FirstItem();
+ while (item) {
+ Entry* entry = item->GetData();
+ if (entry->m_TrackId == track_id) {
+ const char* name = entry->m_Name.GetChars();
+ const char* value = NULL;
+ AP4_Size name_len = 0;
+ AP4_Size value_len = 0;
+
+ if (AP4_CompareStrings(name, "ContentId") != 0 &&
+ AP4_CompareStrings(name, "RightsIssuerUrl") != 0 &&
+ AP4_CompareStrings(name, "KID") != 0) {
+ name_len = entry->m_Name.GetLength();
+ value = entry->m_Value.GetChars();
+ value_len = entry->m_Value.GetLength();
+
+ // format is name:value\0
+ if (name && value) {
+ AP4_CopyMemory(data_buffer, name, name_len);
+ data_buffer[name_len] = ':';
+ data_buffer += (1+name_len);
+ AP4_CopyMemory(data_buffer, value, value_len);
+ data_buffer[value_len] = '\0';
+ data_buffer += (1+value_len);
+ }
+ }
+ }
+ item = item->GetNext();
+ }
+
+ // success path
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectedSampleDescription::AP4_ProtectedSampleDescription
++---------------------------------------------------------------------*/
+AP4_ProtectedSampleDescription::AP4_ProtectedSampleDescription(
+ AP4_UI32 format,
+ AP4_SampleDescription* original_sample_description,
+ AP4_UI32 original_format,
+ AP4_UI32 scheme_type,
+ AP4_UI32 scheme_version,
+ const char* scheme_uri,
+ AP4_ContainerAtom* schi,
+ bool transfer_ownership_of_original /* = true */) :
+ AP4_SampleDescription(TYPE_PROTECTED, format, NULL),
+ m_OriginalSampleDescription(original_sample_description),
+ m_OriginalSampleDescriptionIsOwned(transfer_ownership_of_original),
+ m_OriginalFormat(original_format),
+ m_SchemeType(scheme_type),
+ m_SchemeVersion(scheme_version),
+ m_SchemeUri(scheme_uri)
+{
+ m_SchemeInfo = new AP4_ProtectionSchemeInfo(schi);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectedSampleDescription::~AP4_ProtectedSampleDescription
++---------------------------------------------------------------------*/
+AP4_ProtectedSampleDescription::~AP4_ProtectedSampleDescription()
+{
+ delete m_SchemeInfo;
+ if (m_OriginalSampleDescriptionIsOwned) delete m_OriginalSampleDescription;
+}
+
+/*----------------------------------------------------------------------
+| AP4_ProtectedSampleDescription::ToAtom
++---------------------------------------------------------------------*/
+AP4_Atom*
+AP4_ProtectedSampleDescription::ToAtom() const
+{
+ // construct the atom for the original sample description
+ if (m_OriginalSampleDescription == NULL) return NULL;
+ AP4_Atom* atom = m_OriginalSampleDescription->ToAtom();
+
+ // switch the atom type
+ atom->SetType(m_Format);
+
+ // check that the constructed atom is a container
+ AP4_ContainerAtom* container = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
+ if (container == NULL) return atom; // not a container ?? return now.
+
+ // create the sinf atom
+ AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF);
+
+ // create and add a frma atom
+ AP4_FrmaAtom* frma = new AP4_FrmaAtom(m_OriginalFormat);
+ sinf->AddChild(frma);
+
+ // create and add a schm atom
+ AP4_SchmAtom* schm = new AP4_SchmAtom(m_SchemeType, m_SchemeVersion, m_SchemeUri.GetChars());
+ sinf->AddChild(schm);
+
+ // add the schi atom
+ if (m_SchemeInfo && m_SchemeInfo->GetSchiAtom()) {
+ sinf->AddChild(m_SchemeInfo->GetSchiAtom()->Clone());
+ }
+
+ // add the sinf to the returned atom
+ container->AddChild(sinf);
+
+ return atom;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SampleDecrypter:Create
++---------------------------------------------------------------------*/
+AP4_SampleDecrypter*
+AP4_SampleDecrypter::Create(AP4_ProtectedSampleDescription* sample_description,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory)
+{
+ if (sample_description == NULL || key == NULL) return NULL;
+
+ // select the block cipher factory
+ if (block_cipher_factory == NULL) {
+ block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
+ }
+
+ switch(sample_description->GetSchemeType()) {
+ case AP4_PROTECTION_SCHEME_TYPE_OMA: {
+ AP4_OmaDcfSampleDecrypter* decrypter = NULL;
+ AP4_Result result = AP4_OmaDcfSampleDecrypter::Create(sample_description,
+ key,
+ key_size,
+ block_cipher_factory,
+ decrypter);
+ if (AP4_FAILED(result)) return NULL;
+ return decrypter;
+ }
+
+ case AP4_PROTECTION_SCHEME_TYPE_IAEC: {
+ AP4_IsmaCipher* decrypter = NULL;
+ AP4_Result result = AP4_IsmaCipher::CreateSampleDecrypter(sample_description,
+ key,
+ key_size,
+ block_cipher_factory,
+ decrypter);
+ if (AP4_FAILED(result)) return NULL;
+ return decrypter;
+ }
+
+ case AP4_PROTECTION_SCHEME_TYPE_PIFF: {
+ AP4_PiffSampleDecrypter* decrypter = NULL;
+ AP4_Result result = AP4_PiffSampleDecrypter::Create(sample_description,
+ NULL,
+ key,
+ key_size,
+ block_cipher_factory,
+ decrypter);
+ if (AP4_FAILED(result)) return NULL;
+ return decrypter;
+ }
+
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SampleDecrypter:Create
++---------------------------------------------------------------------*/
+AP4_SampleDecrypter*
+AP4_SampleDecrypter::Create(AP4_ProtectedSampleDescription* sample_description,
+ AP4_ContainerAtom* traf,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory)
+{
+ if (sample_description == NULL || traf == NULL || key == NULL) return NULL;
+
+ // select the block cipher factory
+ if (block_cipher_factory == NULL) {
+ block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
+ }
+
+ switch(sample_description->GetSchemeType()) {
+ case AP4_PROTECTION_SCHEME_TYPE_PIFF: {
+ AP4_PiffSampleDecrypter* decrypter = NULL;
+ AP4_Result result = AP4_PiffSampleDecrypter::Create(sample_description,
+ traf,
+ key,
+ key_size,
+ block_cipher_factory,
+ decrypter);
+ if (AP4_FAILED(result)) return NULL;
+ return decrypter;
+ }
+
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_StandardDecryptingProcessor:AP4_StandardDecryptingProcessor
++---------------------------------------------------------------------*/
+AP4_StandardDecryptingProcessor::AP4_StandardDecryptingProcessor(
+ const AP4_ProtectionKeyMap* key_map /* = NULL */,
+ AP4_BlockCipherFactory* block_cipher_factory /* = NULL */)
+{
+ if (key_map) {
+ // copy the keys
+ m_KeyMap.SetKeys(*key_map);
+ }
+
+ if (block_cipher_factory == NULL) {
+ m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
+ } else {
+ m_BlockCipherFactory = block_cipher_factory;
+ }
+}
+
+/*----------------------------------------------------------------------
+ | AP4_StandardDecryptingProcessor:Initialize
+ +---------------------------------------------------------------------*/
+AP4_Result
+AP4_StandardDecryptingProcessor::Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& /*stream*/,
+ ProgressListener* /*listener*/)
+{
+ AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
+ if (ftyp) {
+ // remove the atom, it will be replaced with a new one
+ top_level.RemoveChild(ftyp);
+
+ // keep the existing brand and compatible brands except for the ones we want to remove
+ AP4_Array<AP4_UI32> compatible_brands;
+ compatible_brands.EnsureCapacity(ftyp->GetCompatibleBrands().ItemCount());
+ for (unsigned int i=0; i<ftyp->GetCompatibleBrands().ItemCount(); i++) {
+ if (ftyp->GetCompatibleBrands()[i] != AP4_OMA_DCF_BRAND_OPF2) {
+ compatible_brands.Append(ftyp->GetCompatibleBrands()[i]);
+ }
+ }
+
+ // create a replacement for the major brand
+ top_level.AddChild(new AP4_FtypAtom(ftyp->GetMajorBrand(),
+ ftyp->GetMinorVersion(),
+ &compatible_brands[0],
+ compatible_brands.ItemCount()), 0);
+ delete ftyp;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_StandardDecryptingProcessor:CreateTrackHandler
++---------------------------------------------------------------------*/
+AP4_Processor::TrackHandler*
+AP4_StandardDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
+{
+ // find the stsd atom
+ AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
+
+ // avoid tracks with no stsd atom (should not happen)
+ if (stsd == NULL) return NULL;
+
+ // we only look at the first sample description
+ AP4_SampleDescription* desc = stsd->GetSampleDescription(0);
+ AP4_SampleEntry* entry = stsd->GetSampleEntry(0);
+ if (desc == NULL || entry == NULL) return NULL;
+ if (desc->GetType() == AP4_SampleDescription::TYPE_PROTECTED) {
+ // create a handler for this track
+ AP4_ProtectedSampleDescription* protected_desc =
+ static_cast<AP4_ProtectedSampleDescription*>(desc);
+ if (protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_OMA) {
+ const AP4_UI08* key = m_KeyMap.GetKey(trak->GetId());
+ if (key) {
+ AP4_OmaDcfTrackDecrypter* handler = NULL;
+ AP4_Result result = AP4_OmaDcfTrackDecrypter::Create(key,
+ AP4_CIPHER_BLOCK_SIZE,
+ protected_desc,
+ entry,
+ m_BlockCipherFactory,
+ handler);
+ if (AP4_FAILED(result)) return NULL;
+ return handler;
+ }
+ } else if (protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_IAEC) {
+ const AP4_UI08* key = m_KeyMap.GetKey(trak->GetId());
+ if (key) {
+ AP4_IsmaTrackDecrypter* handler = NULL;
+ AP4_Result result = AP4_IsmaTrackDecrypter::Create(key,
+ AP4_CIPHER_BLOCK_SIZE,
+ protected_desc,
+ entry,
+ m_BlockCipherFactory,
+ handler);
+ if (AP4_FAILED(result)) return NULL;
+ return handler;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::AP4_DecryptingStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DecryptingStream::Create(CipherMode mode,
+ AP4_ByteStream& encrypted_stream,
+ AP4_LargeSize cleartext_size,
+ const AP4_UI08* iv,
+ AP4_Size iv_size,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream)
+{
+ // default return value
+ stream = NULL;
+
+ // default cipher settings
+ if (block_cipher_factory == NULL) {
+ block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
+ }
+
+ // get the encrypted size (includes padding)
+ AP4_LargeSize encrypted_size = 0;
+ AP4_Result result = encrypted_stream.GetSize(encrypted_size);
+ if (AP4_FAILED(result)) return result;
+
+ // check IV
+ if (iv == NULL || iv_size != 16) return AP4_ERROR_INVALID_PARAMETERS;
+
+ // check that the encrypted size is consistent with the cipher mode
+ if (mode == CIPHER_MODE_CBC) {
+ // we need at least 32 bytes of data+padding
+ // we also need a multiple of the block size
+ if (encrypted_size < 32 || ((encrypted_size % 16) != 0)) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+ }
+
+ // create the stream cipher
+ AP4_BlockCipher* block_cipher;
+ result = block_cipher_factory->Create(AP4_BlockCipher::AES_128,
+ (mode == CIPHER_MODE_CTR ?
+ AP4_BlockCipher::ENCRYPT :
+ AP4_BlockCipher::DECRYPT),
+ key, key_size, block_cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // keep a reference to the source stream
+ encrypted_stream.AddReference();
+
+ // create the stream
+ AP4_DecryptingStream* dec_stream = new AP4_DecryptingStream();
+ stream = dec_stream;
+ dec_stream->m_Mode = mode;
+ dec_stream->m_CleartextSize = cleartext_size;
+ dec_stream->m_CleartextPosition = 0;
+ dec_stream->m_EncryptedSize = encrypted_size;
+ dec_stream->m_EncryptedStream = &encrypted_stream;
+ dec_stream->m_EncryptedPosition = 0;
+ dec_stream->m_BufferFullness = 0;
+ dec_stream->m_BufferOffset = 0;
+ dec_stream->m_ReferenceCount = 1;
+
+ // create the cipher according to the mode
+ switch (mode) {
+ case CIPHER_MODE_CBC:
+ dec_stream->m_StreamCipher = new AP4_CbcStreamCipher(block_cipher,
+ AP4_StreamCipher::DECRYPT);
+ break;
+ case CIPHER_MODE_CTR:
+ dec_stream->m_StreamCipher = new AP4_CtrStreamCipher(block_cipher,
+ NULL,
+ AP4_CIPHER_BLOCK_SIZE);
+ break;
+ default:
+ // should never occur
+ AP4_ASSERT(0);
+ }
+
+ // set the IV
+ dec_stream->m_StreamCipher->SetIV(iv);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::~AP4_DecryptingStream
++---------------------------------------------------------------------*/
+AP4_DecryptingStream::~AP4_DecryptingStream()
+{
+ delete m_StreamCipher;
+ m_EncryptedStream->Release();
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::AddReference
++---------------------------------------------------------------------*/
+void
+AP4_DecryptingStream::AddReference()
+{
+ ++m_ReferenceCount;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::Release
++---------------------------------------------------------------------*/
+void
+AP4_DecryptingStream::Release()
+{
+ if (--m_ReferenceCount == 0) delete this;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::ReadPartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DecryptingStream::ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read)
+{
+ bytes_read = 0;
+
+ // never read more than what's available
+ AP4_LargeSize available = m_CleartextSize-m_CleartextPosition;
+ if (available < bytes_to_read) {
+ if (available == 0) {
+ return AP4_ERROR_EOS;
+ }
+ bytes_to_read = (AP4_Size)available;
+ }
+
+ if (m_BufferFullness) {
+ // we have some leftovers
+ AP4_Size chunk = bytes_to_read;
+ if (chunk > m_BufferFullness) chunk = m_BufferFullness;
+ AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
+ buffer = (char*)buffer+chunk;
+ m_CleartextPosition += chunk;
+ available -= chunk;
+ bytes_to_read -= chunk;
+ m_BufferFullness -= chunk;
+ m_BufferOffset += chunk;
+ bytes_read += chunk;
+ }
+
+ // seek to the right place in the input
+ m_EncryptedStream->Seek(m_EncryptedPosition);
+
+ while (bytes_to_read) {
+ // read from the source
+ AP4_UI08 encrypted[16];
+ AP4_Size encrypted_read = 0;
+ AP4_Result result = m_EncryptedStream->ReadPartial(encrypted, 16, encrypted_read);
+ if (result == AP4_ERROR_EOS) {
+ if (bytes_read == 0) {
+ return AP4_ERROR_EOS;
+ } else {
+ return AP4_SUCCESS;
+ }
+ } else if (result != AP4_SUCCESS) {
+ return result;
+ } else {
+ m_EncryptedPosition += encrypted_read;
+ }
+ bool is_last_buffer = (m_EncryptedPosition >= m_EncryptedSize);
+ AP4_Size buffer_size = 16;
+ result = m_StreamCipher->ProcessBuffer(encrypted,
+ encrypted_read,
+ m_Buffer,
+ &buffer_size,
+ is_last_buffer);
+ m_BufferOffset = 0;
+ m_BufferFullness = buffer_size;
+
+ AP4_Size chunk = bytes_to_read;
+ if (chunk > m_BufferFullness) chunk = m_BufferFullness;
+ AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
+ buffer = (char*)buffer+chunk;
+ m_CleartextPosition += chunk;
+ available -= chunk;
+ bytes_to_read -= chunk;
+ m_BufferFullness -= chunk;
+ m_BufferOffset += chunk;
+ bytes_read += chunk;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::WritePartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DecryptingStream::WritePartial(const void* /* buffer */,
+ AP4_Size /* bytes_to_write */,
+ AP4_Size& /* bytes_written */)
+{
+ return AP4_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::Seek
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DecryptingStream::Seek(AP4_Position position)
+{
+ AP4_Cardinal preroll = 0;
+
+ // check bounds
+ if (position > m_CleartextSize) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+
+ // try to put the stream cipher at the right offset
+ AP4_CHECK(m_StreamCipher->SetStreamOffset(position, &preroll));
+
+ // seek in the source stream
+ AP4_CHECK(m_EncryptedStream->Seek(position-preroll));
+
+ // if we need to, process the preroll bytes
+ if (preroll > 0) {
+ AP4_Size out_size = 0;
+ AP4_UI08 buffer[2*AP4_CIPHER_BLOCK_SIZE]; // bigger than preroll
+ AP4_CHECK(m_EncryptedStream->Read(buffer, preroll));
+ AP4_CHECK(m_StreamCipher->ProcessBuffer(buffer, preroll, buffer, &out_size));
+ AP4_ASSERT(out_size == 0); // we're just feeding prerolled bytes,
+ // there can be no output
+ }
+
+ // update the counters
+ m_CleartextPosition = position;
+ m_EncryptedPosition = position;
+ m_BufferFullness = 0;
+ m_BufferOffset = 0;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::Tell
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DecryptingStream::Tell(AP4_Position& position)
+{
+ position = m_CleartextPosition;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream::GetSize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DecryptingStream::GetSize(AP4_LargeSize& size)
+{
+ size = m_CleartextSize;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::AP4_EncryptingStream
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_EncryptingStream::Create(CipherMode mode,
+ AP4_ByteStream& cleartext_stream,
+ const AP4_UI08* iv,
+ AP4_Size iv_size,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ bool prepend_iv,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream)
+{
+ // default return value
+ stream = NULL;
+
+ // get the cleartext size
+ AP4_LargeSize cleartext_size = 0;
+ AP4_Result result = cleartext_stream.GetSize(cleartext_size);
+ if (AP4_FAILED(result)) return result;
+
+ // check IV
+ if (iv == NULL || iv_size != 16) return AP4_ERROR_INVALID_PARAMETERS;
+
+ // compute the encrypted size
+ AP4_LargeSize encrypted_size = cleartext_size;
+ if (mode == CIPHER_MODE_CBC) {
+ encrypted_size += (16-(cleartext_size%16)); // with padding
+ }
+
+ // create the stream cipher
+ AP4_BlockCipher* block_cipher;
+ result = block_cipher_factory->Create(AP4_BlockCipher::AES_128,
+ AP4_BlockCipher::ENCRYPT,
+ key, key_size, block_cipher);
+ if (AP4_FAILED(result)) return result;
+
+ // keep a reference to the source stream
+ cleartext_stream.AddReference();
+
+ // create the stream
+ AP4_EncryptingStream* enc_stream = new AP4_EncryptingStream();
+ stream = enc_stream;
+ enc_stream->m_Mode = mode;
+ enc_stream->m_CleartextStream = &cleartext_stream;
+ enc_stream->m_CleartextSize = cleartext_size;
+ enc_stream->m_CleartextPosition = 0;
+ enc_stream->m_EncryptedSize = encrypted_size;
+ enc_stream->m_EncryptedPosition = 0;
+ enc_stream->m_BufferFullness = 0;
+ enc_stream->m_BufferOffset = 0;
+ enc_stream->m_ReferenceCount = 1;
+
+ // deal with the prepended IV if required
+ if (prepend_iv) {
+ enc_stream->m_EncryptedSize += 16;
+ enc_stream->m_BufferFullness = 16;
+ AP4_CopyMemory(enc_stream->m_Buffer, iv, 16);
+ }
+
+ // create the cipher according to the mode
+ switch (mode) {
+ case CIPHER_MODE_CBC:
+ enc_stream->m_StreamCipher = new AP4_CbcStreamCipher(block_cipher,
+ AP4_StreamCipher::ENCRYPT);
+ break;
+ case CIPHER_MODE_CTR:
+ enc_stream->m_StreamCipher = new AP4_CtrStreamCipher(block_cipher,
+ NULL,
+ AP4_CIPHER_BLOCK_SIZE);
+ break;
+ default:
+ // should never occur
+ AP4_ASSERT(0);
+ }
+
+ // set the IV
+ enc_stream->m_StreamCipher->SetIV(iv);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::~AP4_EncryptingStream
++---------------------------------------------------------------------*/
+AP4_EncryptingStream::~AP4_EncryptingStream()
+{
+ delete m_StreamCipher;
+ m_CleartextStream->Release();
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::AddReference
++---------------------------------------------------------------------*/
+void
+AP4_EncryptingStream::AddReference()
+{
+ ++m_ReferenceCount;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::Release
++---------------------------------------------------------------------*/
+void
+AP4_EncryptingStream::Release()
+{
+ if (--m_ReferenceCount == 0) delete this;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::ReadPartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_EncryptingStream::ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read)
+{
+ bytes_read = 0;
+
+ // never read more than what's available
+ AP4_LargeSize available = m_EncryptedSize-m_EncryptedPosition;
+ if (available < bytes_to_read) {
+ if (available == 0) return AP4_ERROR_EOS;
+ bytes_to_read = (AP4_Size)available;
+ }
+
+ if (m_BufferFullness) {
+ // we have some leftovers
+ AP4_Size chunk = bytes_to_read;
+ if (chunk > m_BufferFullness) chunk = m_BufferFullness;
+ AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
+ buffer = (char*)buffer+chunk;
+ m_EncryptedPosition += chunk;
+ available -= chunk;
+ bytes_to_read -= chunk;
+ m_BufferFullness -= chunk;
+ m_BufferOffset += chunk;
+ bytes_read += chunk;
+ }
+
+ // seek to the right place in the input
+ m_CleartextStream->Seek(m_CleartextPosition);
+
+ while (bytes_to_read) {
+ // read from the source
+ AP4_UI08 cleartext[16];
+ AP4_Size cleartext_read = 0;
+ AP4_Result result = m_CleartextStream->ReadPartial(cleartext, 16, cleartext_read);
+ if (result == AP4_ERROR_EOS) {
+ if (bytes_read == 0) {
+ return AP4_ERROR_EOS;
+ } else {
+ return AP4_SUCCESS;
+ }
+ } else if (result != AP4_SUCCESS) {
+ return result;
+ } else {
+ m_CleartextPosition += cleartext_read;
+ }
+ bool is_last_buffer = (m_CleartextPosition >= m_CleartextSize);
+ AP4_Size buffer_size = 32; // enough for one block plus one block padding
+ result = m_StreamCipher->ProcessBuffer(cleartext,
+ cleartext_read,
+ m_Buffer,
+ &buffer_size,
+ is_last_buffer);
+ m_BufferOffset = 0;
+ m_BufferFullness = buffer_size;
+
+ AP4_Size chunk = bytes_to_read;
+ if (chunk > m_BufferFullness) chunk = m_BufferFullness;
+ if (chunk) {
+ AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
+ buffer = (char*)buffer+chunk;
+ m_EncryptedPosition += chunk;
+ available -= chunk;
+ bytes_to_read -= chunk;
+ m_BufferFullness -= chunk;
+ m_BufferOffset += chunk;
+ bytes_read += chunk;
+ }
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::WritePartial
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_EncryptingStream::WritePartial(const void* /* buffer */,
+ AP4_Size /* bytes_to_write */,
+ AP4_Size& /* bytes_written */)
+{
+ return AP4_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::Seek
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_EncryptingStream::Seek(AP4_Position position)
+{
+ if (position == m_EncryptedPosition) {
+ return AP4_SUCCESS;
+ } else {
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::Tell
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_EncryptingStream::Tell(AP4_Position& position)
+{
+ position = m_EncryptedPosition;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream::GetSize
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_EncryptingStream::GetSize(AP4_LargeSize& size)
+{
+ size = m_EncryptedSize;
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DefaultBlockCipherFactory::Instance
++---------------------------------------------------------------------*/
+AP4_DefaultBlockCipherFactory AP4_DefaultBlockCipherFactory::Instance;
+
+/*----------------------------------------------------------------------
+| AP4_DefaultBlockCipherFactory
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DefaultBlockCipherFactory::Create(AP4_BlockCipher::CipherType type,
+ AP4_BlockCipher::CipherDirection direction,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipher*& cipher)
+{
+ // setup default return vaule
+ cipher = NULL;
+
+ switch (type) {
+ case AP4_BlockCipher::AES_128:
+ // check cipher parameters
+ if (key == NULL || key_size != AP4_AES_BLOCK_SIZE) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+
+ // create the cipher
+ cipher = new AP4_AesBlockCipher(key, direction);
+ return AP4_SUCCESS;
+
+ default:
+ // not supported
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Protection.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Protection.h new file mode 100644 index 000000000..1979193ad --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Protection.h @@ -0,0 +1,479 @@ +/*****************************************************************
+|
+| AP4 - Protected Streams support
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+#ifndef _AP4_PROTECTION_H_
+#define _AP4_PROTECTION_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4SampleEntry.h"
+#include "Ap4Atom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4SampleDescription.h"
+#include "Ap4Processor.h"
+
+/*----------------------------------------------------------------------
+| classes
++---------------------------------------------------------------------*/
+class AP4_StreamCipher;
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+// this is fixed for now
+const unsigned int AP4_PROTECTION_KEY_LENGTH = 16;
+
+const AP4_UI32 AP4_PROTECTION_SCHEME_TYPE_ITUNES = AP4_ATOM_TYPE('i','t','u','n');
+
+/*----------------------------------------------------------------------
+| AP4_EncaSampleEntry
++---------------------------------------------------------------------*/
+class AP4_EncaSampleEntry : public AP4_AudioSampleEntry
+{
+public:
+ // methods
+ AP4_EncaSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory);
+ AP4_EncaSampleEntry(AP4_UI32 type,
+ AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory);
+
+ // methods
+ AP4_SampleDescription* ToSampleDescription();
+
+ // this method is used as a factory by the ISMACryp classes
+ // NOTE: this should be named ToSampleDescription, but C++ has a
+ // problem with that because the base class does not have this
+ // overloaded method, but has another other one by that name
+ virtual AP4_SampleDescription* ToTargetSampleDescription(AP4_UI32 format);
+};
+
+/*----------------------------------------------------------------------
+| AP4_EncvSampleEntry
++---------------------------------------------------------------------*/
+class AP4_EncvSampleEntry : public AP4_VisualSampleEntry
+{
+public:
+ // constructors
+ AP4_EncvSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory);
+ AP4_EncvSampleEntry(AP4_UI32 type,
+ AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory);
+
+ // methods
+ AP4_SampleDescription* ToSampleDescription();
+
+ // this method is used as a factory by the ISMACryp classes
+ // NOTE: this should be named ToSampleDescription, but C++ has a
+ // problem with that because the base class does not have this
+ // overloaded method, but has another other one by that name
+ virtual AP4_SampleDescription* ToTargetSampleDescription(AP4_UI32 format);
+};
+
+/*----------------------------------------------------------------------
+| AP4_DrmsSampleEntry
++---------------------------------------------------------------------*/
+class AP4_DrmsSampleEntry : public AP4_EncaSampleEntry
+{
+public:
+ // methods
+ AP4_DrmsSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory);
+};
+
+/*----------------------------------------------------------------------
+| AP4_DrmiSampleEntry
++---------------------------------------------------------------------*/
+class AP4_DrmiSampleEntry : public AP4_EncvSampleEntry
+{
+public:
+ // methods
+ AP4_DrmiSampleEntry(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory);
+};
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionKeyMap
++---------------------------------------------------------------------*/
+class AP4_ProtectionKeyMap
+{
+public:
+ // constructors and destructor
+ AP4_ProtectionKeyMap();
+ ~AP4_ProtectionKeyMap();
+
+ // methods
+ AP4_Result SetKey(AP4_UI32 track_id, const AP4_UI08* key, const AP4_UI08* iv = NULL);
+ AP4_Result SetKeys(const AP4_ProtectionKeyMap& key_map);
+ AP4_Result GetKeyAndIv(AP4_UI32 track_id, const AP4_UI08*& key, const AP4_UI08*& iv);
+ const AP4_UI08* GetKey(AP4_UI32 track_id) const;
+
+private:
+ // types
+ class KeyEntry {
+ public:
+ KeyEntry(AP4_UI32 track_id, const AP4_UI08* key, const AP4_UI08* iv = NULL);
+ void SetKey(const AP4_UI08* key, const AP4_UI08* iv);
+ AP4_Ordinal m_TrackId;
+ AP4_UI08 m_Key[AP4_PROTECTION_KEY_LENGTH];
+ AP4_UI08 m_IV[AP4_PROTECTION_KEY_LENGTH];
+ };
+
+ // methods
+ KeyEntry* GetEntry(AP4_UI32 track_id) const;
+
+ // members
+ AP4_List<KeyEntry> m_KeyEntries;
+};
+
+/*----------------------------------------------------------------------
+| AP4_TrackPropertyMap
++---------------------------------------------------------------------*/
+class AP4_TrackPropertyMap
+{
+public:
+ // methods
+ AP4_Result SetProperty(AP4_UI32 track_id, const char* name, const char* value);
+ AP4_Result SetProperties(const AP4_TrackPropertyMap& properties);
+ const char* GetProperty(AP4_UI32 track_id, const char* name);
+ AP4_Result GetTextualHeaders(AP4_UI32 track_id, AP4_DataBuffer& buffer);
+
+
+ // destructor
+ virtual ~AP4_TrackPropertyMap();
+
+private:
+ // types
+ class Entry {
+ public:
+ Entry(AP4_UI32 track_id, const char* name, const char* value) :
+ m_TrackId(track_id), m_Name(name), m_Value(value) {}
+ AP4_UI32 m_TrackId;
+ AP4_String m_Name;
+ AP4_String m_Value;
+ };
+
+ // members
+ AP4_List<Entry> m_Entries;
+};
+
+/*----------------------------------------------------------------------
+| AP4_ProtectionSchemeInfo
++---------------------------------------------------------------------*/
+class AP4_ProtectionSchemeInfo
+{
+public:
+ // constructors and destructor
+ AP4_ProtectionSchemeInfo(AP4_ContainerAtom* schi);
+ virtual ~AP4_ProtectionSchemeInfo();
+
+ // accessors
+ AP4_ContainerAtom* GetSchiAtom() { return m_SchiAtom; }
+
+protected:
+ AP4_ContainerAtom* m_SchiAtom;
+};
+
+/*----------------------------------------------------------------------
+| AP4_ProtectedSampleDescription
++---------------------------------------------------------------------*/
+class AP4_ProtectedSampleDescription : public AP4_SampleDescription
+{
+public:
+ AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_ProtectedSampleDescription, AP4_SampleDescription)
+
+ // constructor and destructor
+ AP4_ProtectedSampleDescription(AP4_UI32 format,
+ AP4_SampleDescription* original_sample_description,
+ AP4_UI32 original_format,
+ AP4_UI32 scheme_type,
+ AP4_UI32 scheme_version,
+ const char* scheme_uri,
+ AP4_ContainerAtom* schi_atom, // will be cloned
+ bool transfer_ownership_of_original=true);
+ ~AP4_ProtectedSampleDescription();
+
+ // accessors
+ AP4_SampleDescription* GetOriginalSampleDescription() {
+ return m_OriginalSampleDescription;
+ }
+ AP4_UI32 GetOriginalFormat() const { return m_OriginalFormat; }
+ AP4_UI32 GetSchemeType() const { return m_SchemeType; }
+ AP4_UI32 GetSchemeVersion() const { return m_SchemeVersion; }
+ const AP4_String& GetSchemeUri() const { return m_SchemeUri; }
+ AP4_ProtectionSchemeInfo* GetSchemeInfo() const {
+ return m_SchemeInfo;
+ }
+
+ // implementation of abstract base class methods
+ virtual AP4_Atom* ToAtom() const;
+
+private:
+ // members
+ AP4_SampleDescription* m_OriginalSampleDescription;
+ bool m_OriginalSampleDescriptionIsOwned;
+ AP4_UI32 m_OriginalFormat;
+ AP4_UI32 m_SchemeType;
+ AP4_UI32 m_SchemeVersion;
+ AP4_String m_SchemeUri;
+ AP4_ProtectionSchemeInfo* m_SchemeInfo;
+};
+
+/*----------------------------------------------------------------------
+| AP4_BlockCipher
++---------------------------------------------------------------------*/
+class AP4_BlockCipher
+{
+public:
+ // types
+ typedef enum {
+ ENCRYPT,
+ DECRYPT
+ } CipherDirection;
+
+ typedef enum {
+ AES_128
+ } CipherType;
+
+ // constructor and destructor
+ virtual ~AP4_BlockCipher() {}
+
+ // methods
+ virtual AP4_Result ProcessBlock(const AP4_UI08* block_in, AP4_UI08* block_out) = 0;
+};
+
+/*----------------------------------------------------------------------
+| AP4_BlockCipherFactory
++---------------------------------------------------------------------*/
+class AP4_BlockCipherFactory
+{
+public:
+ // methods
+ virtual ~AP4_BlockCipherFactory() {}
+ virtual AP4_Result Create(AP4_BlockCipher::CipherType type,
+ AP4_BlockCipher::CipherDirection direction,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipher*& cipher) = 0;
+};
+
+/*----------------------------------------------------------------------
+| AP4_DefaultBlockCipherFactory
++---------------------------------------------------------------------*/
+class AP4_DefaultBlockCipherFactory : public AP4_BlockCipherFactory
+{
+public:
+ // class variables
+ static AP4_DefaultBlockCipherFactory Instance;
+
+ // methods
+ virtual AP4_Result Create(AP4_BlockCipher::CipherType type,
+ AP4_BlockCipher::CipherDirection direction,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipher*& cipher);
+};
+
+/*----------------------------------------------------------------------
+| AP4_SampleDecrypter
++---------------------------------------------------------------------*/
+class AP4_SampleDecrypter
+{
+public:
+ /**
+ * Create a sample decrypter given a protected sample description
+ */
+ static AP4_SampleDecrypter* Create(AP4_ProtectedSampleDescription* sample_description,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+
+ /**
+ * Create a fragment sample decrypter given a protected sample description and a track fragment
+ */
+ static AP4_SampleDecrypter* Create(AP4_ProtectedSampleDescription* sample_description,
+ AP4_ContainerAtom* traf,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+
+ // destructor
+ virtual ~AP4_SampleDecrypter() {}
+
+ // methods
+ virtual AP4_Size GetDecryptedSampleSize(AP4_Sample& sample) { return sample.GetSize(); }
+ virtual AP4_Result SetSampleIndex(AP4_Ordinal /*index*/) { return AP4_SUCCESS; }
+ virtual AP4_Result DecryptSampleData(AP4_DataBuffer& data_in,
+ AP4_DataBuffer& data_out,
+ const AP4_UI08* iv = NULL) = 0;
+};
+
+/*----------------------------------------------------------------------
+| AP4_StandardDecryptingProcessor
++---------------------------------------------------------------------*/
+class AP4_StandardDecryptingProcessor : public AP4_Processor
+{
+public:
+ // constructor
+ AP4_StandardDecryptingProcessor(const AP4_ProtectionKeyMap* key_map = NULL,
+ AP4_BlockCipherFactory* block_cipher_factory = NULL);
+
+ // accessors
+ AP4_ProtectionKeyMap& GetKeyMap() { return m_KeyMap; }
+
+ // methods
+ virtual AP4_Result Initialize(AP4_AtomParent& top_level,
+ AP4_ByteStream& stream,
+ ProgressListener* listener);
+ virtual AP4_Processor::TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak);
+
+private:
+ // members
+ AP4_BlockCipherFactory* m_BlockCipherFactory;
+ AP4_ProtectionKeyMap m_KeyMap;
+};
+
+/*----------------------------------------------------------------------
+| AP4_DecryptingStream
++---------------------------------------------------------------------*/
+class AP4_DecryptingStream : public AP4_ByteStream {
+public:
+ typedef enum {
+ CIPHER_MODE_CTR,
+ CIPHER_MODE_CBC
+ } CipherMode;
+
+ static AP4_Result Create(CipherMode mode,
+ AP4_ByteStream& encrypted_stream,
+ AP4_LargeSize cleartext_size,
+ const AP4_UI08* iv,
+ AP4_Size iv_size,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream);
+
+ // AP4_ByteStream methods
+ virtual AP4_Result ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read);
+ virtual AP4_Result WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written);
+ virtual AP4_Result Seek(AP4_Position position);
+ virtual AP4_Result Tell(AP4_Position& position);
+ virtual AP4_Result GetSize(AP4_LargeSize& size);
+
+ // AP4_Referenceable methods
+ virtual void AddReference();
+ virtual void Release();
+
+private:
+ // methods
+ AP4_DecryptingStream() {} // private constructor, use the factory instead
+ ~AP4_DecryptingStream();
+
+ // members
+ CipherMode m_Mode;
+ AP4_LargeSize m_CleartextSize;
+ AP4_Position m_CleartextPosition;
+ AP4_ByteStream* m_EncryptedStream;
+ AP4_LargeSize m_EncryptedSize;
+ AP4_Position m_EncryptedPosition;
+ AP4_StreamCipher* m_StreamCipher;
+ AP4_UI08 m_Buffer[16];
+ AP4_Size m_BufferFullness;
+ AP4_Size m_BufferOffset;
+ AP4_Cardinal m_ReferenceCount;
+};
+
+/*----------------------------------------------------------------------
+| AP4_EncryptingStream
++---------------------------------------------------------------------*/
+class AP4_EncryptingStream : public AP4_ByteStream {
+public:
+ typedef enum {
+ CIPHER_MODE_CTR,
+ CIPHER_MODE_CBC
+ } CipherMode;
+
+ static AP4_Result Create(CipherMode mode,
+ AP4_ByteStream& cleartext_stream,
+ const AP4_UI08* iv,
+ AP4_Size iv_size,
+ const AP4_UI08* key,
+ AP4_Size key_size,
+ bool prepend_iv,
+ AP4_BlockCipherFactory* block_cipher_factory,
+ AP4_ByteStream*& stream);
+
+ // AP4_ByteStream methods
+ virtual AP4_Result ReadPartial(void* buffer,
+ AP4_Size bytes_to_read,
+ AP4_Size& bytes_read);
+ virtual AP4_Result WritePartial(const void* buffer,
+ AP4_Size bytes_to_write,
+ AP4_Size& bytes_written);
+ virtual AP4_Result Seek(AP4_Position position);
+ virtual AP4_Result Tell(AP4_Position& position);
+ virtual AP4_Result GetSize(AP4_LargeSize& size);
+
+ // AP4_Referenceable methods
+ virtual void AddReference();
+ virtual void Release();
+
+private:
+ // methods
+ AP4_EncryptingStream() {} // private constructor, use the factory instead
+ ~AP4_EncryptingStream();
+
+ // members
+ CipherMode m_Mode;
+ AP4_LargeSize m_CleartextSize;
+ AP4_Position m_CleartextPosition;
+ AP4_ByteStream* m_CleartextStream;
+ AP4_LargeSize m_EncryptedSize;
+ AP4_Position m_EncryptedPosition;
+ AP4_StreamCipher* m_StreamCipher;
+ AP4_UI08 m_Buffer[32]; // one cipher block plus one block padding
+ AP4_Size m_BufferFullness;
+ AP4_Size m_BufferOffset;
+ AP4_Cardinal m_ReferenceCount;
+};
+
+
+#endif // _AP4_PROTECTION_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Results.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Results.cpp new file mode 100644 index 000000000..1bb2c5cd8 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Results.cpp @@ -0,0 +1,68 @@ +/***************************************************************** +| +| Bento4 - Result Code Map +| +| This file is automatically generated by a script, do not edit! +| +| Copyright (c) 2002-2009, Axiomatic Systems, LLC. +| All rights reserved. +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Results.h" + +/*---------------------------------------------------------------------- +| AP4_ResultText ++---------------------------------------------------------------------*/ +const char* +AP4_ResultText(int result) +{ + switch (result) { + case AP4_SUCCESS: return "AP4_SUCCESS"; + case AP4_FAILURE: return "AP4_FAILURE"; + case AP4_ERROR_OUT_OF_MEMORY: return "AP4_ERROR_OUT_OF_MEMORY"; + case AP4_ERROR_INVALID_PARAMETERS: return "AP4_ERROR_INVALID_PARAMETERS"; + case AP4_ERROR_NO_SUCH_FILE: return "AP4_ERROR_NO_SUCH_FILE"; + case AP4_ERROR_PERMISSION_DENIED: return "AP4_ERROR_PERMISSION_DENIED"; + case AP4_ERROR_CANNOT_OPEN_FILE: return "AP4_ERROR_CANNOT_OPEN_FILE"; + case AP4_ERROR_EOS: return "AP4_ERROR_EOS"; + case AP4_ERROR_WRITE_FAILED: return "AP4_ERROR_WRITE_FAILED"; + case AP4_ERROR_READ_FAILED: return "AP4_ERROR_READ_FAILED"; + case AP4_ERROR_INVALID_FORMAT: return "AP4_ERROR_INVALID_FORMAT"; + case AP4_ERROR_NO_SUCH_ITEM: return "AP4_ERROR_NO_SUCH_ITEM"; + case AP4_ERROR_OUT_OF_RANGE: return "AP4_ERROR_OUT_OF_RANGE"; + case AP4_ERROR_INTERNAL: return "AP4_ERROR_INTERNAL"; + case AP4_ERROR_INVALID_STATE: return "AP4_ERROR_INVALID_STATE"; + case AP4_ERROR_LIST_EMPTY: return "AP4_ERROR_LIST_EMPTY"; + case AP4_ERROR_LIST_OPERATION_ABORTED: return "AP4_ERROR_LIST_OPERATION_ABORTED"; + case AP4_ERROR_INVALID_RTP_CONSTRUCTOR_TYPE: return "AP4_ERROR_INVALID_RTP_CONSTRUCTOR_TYPE"; + case AP4_ERROR_NOT_SUPPORTED: return "AP4_ERROR_NOT_SUPPORTED"; + case AP4_ERROR_INVALID_TRACK_TYPE: return "AP4_ERROR_INVALID_TRACK_TYPE"; + case AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA: return "AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA"; + case AP4_ERROR_BUFFER_TOO_SMALL: return "AP4_ERROR_BUFFER_TOO_SMALL"; + case AP4_ERROR_NOT_ENOUGH_DATA: return "AP4_ERROR_NOT_ENOUGH_DATA"; + default: return "UNKNOWN"; + } +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Results.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Results.h new file mode 100644 index 000000000..58afaef55 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Results.h @@ -0,0 +1,76 @@ +/*****************************************************************
+|
+| AP4 - Result Codes
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_RESULTS_H_
+#define _AP4_RESULTS_H_
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const int AP4_SUCCESS = 0;
+const int AP4_FAILURE = -1;
+const int AP4_ERROR_OUT_OF_MEMORY = -2;
+const int AP4_ERROR_INVALID_PARAMETERS = -3;
+const int AP4_ERROR_NO_SUCH_FILE = -4;
+const int AP4_ERROR_PERMISSION_DENIED = -5;
+const int AP4_ERROR_CANNOT_OPEN_FILE = -6;
+const int AP4_ERROR_EOS = -7;
+const int AP4_ERROR_WRITE_FAILED = -8;
+const int AP4_ERROR_READ_FAILED = -9;
+const int AP4_ERROR_INVALID_FORMAT = -10;
+const int AP4_ERROR_NO_SUCH_ITEM = -11;
+const int AP4_ERROR_OUT_OF_RANGE = -12;
+const int AP4_ERROR_INTERNAL = -13;
+const int AP4_ERROR_INVALID_STATE = -14;
+const int AP4_ERROR_LIST_EMPTY = -15;
+const int AP4_ERROR_LIST_OPERATION_ABORTED = -16;
+const int AP4_ERROR_INVALID_RTP_CONSTRUCTOR_TYPE = -17;
+const int AP4_ERROR_NOT_SUPPORTED = -18;
+const int AP4_ERROR_INVALID_TRACK_TYPE = -19;
+const int AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA = -20;
+const int AP4_ERROR_BUFFER_TOO_SMALL = -21;
+const int AP4_ERROR_NOT_ENOUGH_DATA = -22;
+const int AP4_ERROR_NOT_ENOUGH_SPACE = -23;
+
+/*----------------------------------------------------------------------
+| utility functions
++---------------------------------------------------------------------*/
+const char* AP4_ResultText(int result);
+
+/*----------------------------------------------------------------------
+| macros
++---------------------------------------------------------------------*/
+#define AP4_FAILED(result) ((result) != AP4_SUCCESS)
+#define AP4_SUCCEEDED(result) ((result) == AP4_SUCCESS)
+
+#define AP4_CHECK(_x) do { \
+ AP4_Result _result = (_x); \
+ if (AP4_FAILED(_result)) return _result; \
+} while(0)
+
+#endif // _AP4_RESULTS_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpAtom.cpp new file mode 100644 index 000000000..ad46363cd --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpAtom.cpp @@ -0,0 +1,92 @@ +/***************************************************************** +| +| AP4 - sdp Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4RtpAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + + +/*---------------------------------------------------------------------- +| AP4_RtpAtom::AP4_RtpAtom ++---------------------------------------------------------------------*/ +AP4_RtpAtom::AP4_RtpAtom(AP4_UI32 size, AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_RTP_, size) +{ + // desc format + stream.ReadUI32(m_DescriptionFormat); + + // sdptext + int str_size = size-(AP4_ATOM_HEADER_SIZE+4); + if (str_size) { + char* str = new char[str_size+1]; + stream.Read(str, str_size); + str[str_size] = '\0'; // force null-termination + m_SdpText = str; + delete[] str; + } +} + +/*---------------------------------------------------------------------- +| AP4_RtpAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // description format + result = stream.WriteUI32(m_DescriptionFormat); + if (AP4_FAILED(result)) return result; + + // sdp text + result = stream.Write(m_SdpText.GetChars(), m_SdpText.GetLength()); + if (AP4_FAILED(result)) return result; + + // pad with zeros if necessary + AP4_Size padding = m_Size32-(AP4_ATOM_HEADER_SIZE+4+m_SdpText.GetLength()); + while (padding--) stream.WriteUI08(0); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_RtpAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpAtom::InspectFields(AP4_AtomInspector& inspector) +{ + char format_string[5]; + AP4_FormatFourChars(format_string, m_DescriptionFormat); + inspector.AddField("description_format", format_string); + inspector.AddField("sdp_text", m_SdpText.GetChars()); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpAtom.h new file mode 100644 index 000000000..596d96cfc --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpAtom.h @@ -0,0 +1,70 @@ +/***************************************************************** +| +| AP4 - rtp Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_RTP_ATOM_H_ +#define _AP4_RTP_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4String.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_RtpAtom ++---------------------------------------------------------------------*/ +class AP4_RtpAtom : public AP4_Atom +{ +public: + // class methods + static AP4_RtpAtom* Create(AP4_Size size, AP4_ByteStream& stream) { + return new AP4_RtpAtom(size, stream); + } + + // methods + const AP4_String& GetSdpText() { return m_SdpText; } + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_RtpAtom(AP4_UI32 size, AP4_ByteStream& stream); + + // members + AP4_UI32 m_DescriptionFormat; + AP4_String m_SdpText; +}; + +#endif // _AP4_RTP_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpHint.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpHint.cpp new file mode 100644 index 000000000..3f9f19c0e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpHint.cpp @@ -0,0 +1,636 @@ +/***************************************************************** +| +| AP4 - RTP Hint Objects +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4RtpHint.h" +#include "Ap4ByteStream.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_RtpSampleData::~AP4_RtpSampleData ++---------------------------------------------------------------------*/ +AP4_RtpSampleData::~AP4_RtpSampleData() +{ + AP4_List<AP4_RtpPacket>::Item* it = m_Packets.FirstItem(); + while (it != NULL) { + it->GetData()->Release(); + it = it->GetNext(); + } +} + +/*---------------------------------------------------------------------- +| AP4_RtpSampleData::AP4_RtpSampleData ++---------------------------------------------------------------------*/ +AP4_RtpSampleData::AP4_RtpSampleData(AP4_ByteStream& stream, AP4_UI32 size) +{ + // save the start position + AP4_Position start, extra_data_start; + stream.Tell(start); + + AP4_UI16 packet_count; + stream.ReadUI16(packet_count); + + AP4_UI16 reserved; + stream.ReadUI16(reserved); // later, check that reserved is 0 + + // packets + for (AP4_UI16 i=0; i<packet_count; i++) { + AP4_RtpPacket* packet = new AP4_RtpPacket(stream); + m_Packets.Add(packet); + } + + // extra data + stream.Tell(extra_data_start); + AP4_Size extra_data_size = size - (AP4_UI32)(extra_data_start-start); + if (extra_data_size != 0) { + m_ExtraData.SetDataSize(extra_data_size); + stream.Read(m_ExtraData.UseData(), extra_data_size); + } +} + +/*---------------------------------------------------------------------- +| AP4_RtpSampleData::GetSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_RtpSampleData::GetSize() +{ + // packet count and reserved + AP4_Size result = 4; + + // packets + AP4_List<AP4_RtpPacket>::Item* it = m_Packets.FirstItem(); + while (it != NULL) { + result = it->GetData()->GetSize(); + it = it->GetNext(); + } + + // extra data + result += m_ExtraData.GetDataSize(); + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_RtpSampleData::ToByteStream ++---------------------------------------------------------------------*/ +AP4_ByteStream* +AP4_RtpSampleData::ToByteStream() +{ + // refresh the size + AP4_Size size = GetSize(); + + // create a memory stream + AP4_MemoryByteStream* stream = new AP4_MemoryByteStream(size); + + // write in it + AP4_Result result = stream->WriteUI16(static_cast<AP4_UI16>(m_Packets.ItemCount())); + if (AP4_FAILED(result)) goto bail; + + result = stream->WriteUI16(0); // reserved + if (AP4_FAILED(result)) goto bail; + + { + AP4_List<AP4_RtpPacket>::Item* it = m_Packets.FirstItem(); + while (it != NULL) { + result = it->GetData()->Write(*stream); + if (AP4_FAILED(result)) goto bail; + it = it->GetNext(); + } + } + + result = stream->Write(m_ExtraData.GetData(), m_ExtraData.GetDataSize()); + if (AP4_FAILED(result)) goto bail; + + // return + return stream; + +bail: + stream->Release(); + return NULL; +} + + +/*---------------------------------------------------------------------- +| AP4_RtpSampleData::AddPacket ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpSampleData::AddPacket(AP4_RtpPacket* packet) +{ + packet->AddReference(); + return m_Packets.Add(packet); +} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::AP4_RtpPacket ++---------------------------------------------------------------------*/ +AP4_RtpPacket::AP4_RtpPacket(int relative_time, + bool p_bit, + bool x_bit, + bool m_bit, + AP4_UI08 payload_type, + AP4_UI16 sequence_seed, + int time_stamp_offset /* = 0 */, + bool bframe_flag /* = false */, + bool repeat_flag /* = false */) : + m_ReferenceCount(1), + m_RelativeTime(relative_time), + m_PBit(p_bit), + m_XBit(x_bit), + m_MBit(m_bit), + m_PayloadType(payload_type), + m_SequenceSeed(sequence_seed), + m_TimeStampOffset(time_stamp_offset), + m_BFrameFlag(bframe_flag), + m_RepeatFlag(repeat_flag) +{} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::AP4_RtpPacket ++---------------------------------------------------------------------*/ +AP4_RtpPacket::AP4_RtpPacket(AP4_ByteStream& stream) : + m_ReferenceCount(1), + m_TimeStampOffset(0) +{ + AP4_UI08 octet; + + // relative time + AP4_UI32 relative_time; + stream.ReadUI32(relative_time); + m_RelativeTime = relative_time; + + // pbit and xbit + stream.ReadUI08(octet); + m_PBit = (octet & 0x20) != 0; + m_XBit = (octet & 0x10) != 0; + + // mbit and payload type + stream.ReadUI08(octet); + m_MBit = (octet & 0x80) != 0; + m_PayloadType = octet & 0x7F; + + // sequence seed + stream.ReadUI16(m_SequenceSeed); + + // extra, bframe and repeat flags + stream.ReadUI08(octet); + stream.ReadUI08(octet); // repeat on purpose + bool extra_flag = (octet & 0x04) != 0; + + // bframe and repeat flags + m_BFrameFlag = (octet & 0x02) != 0; + m_RepeatFlag = (octet & 0x01) != 0; + + // constructor count + AP4_UI16 constructor_count; + stream.ReadUI16(constructor_count); + + // parse the packet extra data + if (extra_flag) { + // read the length + AP4_UI32 extra_length; + stream.ReadUI32(extra_length); + + // check it + if (extra_length < 4) return; + + // now read the entries + extra_length -= 4; + while (extra_length > 0) { + AP4_UI32 entry_length; + AP4_UI32 entry_tag; + stream.ReadUI32(entry_length); + stream.ReadUI32(entry_tag); + + // check the entry + if (entry_length < 8) return; + + // parse the single entry that's currently defined in the spec + if (entry_tag == AP4_ATOM_TYPE('r','t','p','o') && entry_length == 12) { + AP4_UI32 time_stamp_offset; + stream.ReadUI32(time_stamp_offset); + m_TimeStampOffset = time_stamp_offset; + } else { + // ignore it + AP4_Position cur_pos; + stream.Tell(cur_pos); + stream.Seek(cur_pos + entry_length - 8); // 8 = length + tag + } + + extra_length -= entry_length; + } + } + + // constructors + for (AP4_UI16 i=0; i<constructor_count; i++) { + AP4_RtpConstructor* constructor = NULL; + AP4_RtpConstructorFactory::CreateConstructorFromStream(stream, constructor); + m_Constructors.Add(constructor); + } +} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::AP4_RtpPacket ++---------------------------------------------------------------------*/ +AP4_RtpPacket::~AP4_RtpPacket() +{ + AP4_List<AP4_RtpConstructor>::Item* it = m_Constructors.FirstItem(); + while (it != NULL) { + it->GetData()->Release(); + it = it->GetNext(); + } +} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::AddReference ++---------------------------------------------------------------------*/ +void +AP4_RtpPacket::AddReference() +{ + m_ReferenceCount++; +} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::Release ++---------------------------------------------------------------------*/ +void +AP4_RtpPacket::Release() +{ + if (--m_ReferenceCount == 0) { + delete this; + } +} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::GetSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_RtpPacket::GetSize() +{ + AP4_Size result = 12 + (m_TimeStampOffset != 0)?16:0; + result += m_Constructors.ItemCount() * AP4_RTP_CONSTRUCTOR_SIZE; + return result; +} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::Write ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpPacket::Write(AP4_ByteStream& stream) +{ + // check the payload type + if (m_PayloadType > 128) return AP4_FAILURE; + + // now write + AP4_Result result = stream.WriteUI32(m_RelativeTime); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI08(0x80 | m_PBit << 5 | m_XBit << 4); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI08(m_MBit << 7 | m_PayloadType); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI16(m_SequenceSeed); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI08(0); + if (AP4_FAILED(result)) return result; + + // deal with extra flag + bool extra_flag = m_TimeStampOffset != 0; + result = stream.WriteUI08(0x00 | extra_flag << 2 + | m_BFrameFlag << 1 + | m_RepeatFlag << 0); + if (AP4_FAILED(result)) return result; + + + // constructor count + result = stream.WriteUI16(static_cast<AP4_UI16>(m_Constructors.ItemCount())); + + // write extra data + if (extra_flag) { + // extra_length + result = stream.WriteUI32(16); // 4 (extra_length) + 12 (rtpo atom) + if (AP4_FAILED(result)) return result; + + // rtpo atom + result = stream.WriteUI32(12); // size + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(AP4_ATOM_TYPE('r','t','p','o')); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_TimeStampOffset); + if (AP4_FAILED(result)) return result; + } + + // constructors + AP4_List<AP4_RtpConstructor>::Item* it = m_Constructors.FirstItem(); + while (it != NULL) { + result = it->GetData()->Write(stream); + if (AP4_FAILED(result)) return result; + it = it->GetNext(); + } + return result; +} + +/*---------------------------------------------------------------------- +| AP4_RtpPacket::AddConstructor ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpPacket::AddConstructor(AP4_RtpConstructor* constructor) +{ + constructor->AddReference(); + return m_Constructors.Add(constructor); +} + +/*---------------------------------------------------------------------- +| AP4_RtpConstructor::GetConstructedDataSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_RtpPacket::GetConstructedDataSize() +{ + // header + ssrc + AP4_Size size = 12; + + // constructed data from constructors + AP4_List<AP4_RtpConstructor>::Item* constructors_it + = m_Constructors.FirstItem(); + while (constructors_it != NULL) { + size += constructors_it->GetData()->GetConstructedDataSize(); + constructors_it = constructors_it->GetNext(); + } + + return size; +} + + +/*---------------------------------------------------------------------- +| AP4_RtpConstructor::AddReference ++---------------------------------------------------------------------*/ +void +AP4_RtpConstructor::AddReference() +{ + m_ReferenceCount++; +} + +/*---------------------------------------------------------------------- +| AP4_RtpConstructor::Release ++---------------------------------------------------------------------*/ +void +AP4_RtpConstructor::Release() +{ + if (--m_ReferenceCount == 0) { + delete this; + } +} +/*---------------------------------------------------------------------- +| AP4_RtpConstructor::Write ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpConstructor::Write(AP4_ByteStream& stream) +{ + AP4_Result result = stream.WriteUI08(m_Type); + if (AP4_FAILED(result)) return result; + + return DoWrite(stream); +} + +/*---------------------------------------------------------------------- +| AP4_NoopRtpConstructor::AP4_NoopRtpConstructor ++---------------------------------------------------------------------*/ +AP4_NoopRtpConstructor::AP4_NoopRtpConstructor(AP4_ByteStream& stream) : + AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_NOOP) +{ + AP4_Position cur_offset; + stream.Tell(cur_offset); + stream.Seek(cur_offset+15); +} + +/*---------------------------------------------------------------------- +| AP4_NoopRtpConstructor::DoWrite ++---------------------------------------------------------------------*/ +AP4_Result +AP4_NoopRtpConstructor::DoWrite(AP4_ByteStream& stream) +{ + AP4_UI08 pad[15]; + + return stream.Write(pad, sizeof(pad)); +} + +/*---------------------------------------------------------------------- +| AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor ++---------------------------------------------------------------------*/ +AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor(const AP4_DataBuffer& data) : + AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE), + m_Data(data) +{} + +/*---------------------------------------------------------------------- +| AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor ++---------------------------------------------------------------------*/ +AP4_ImmediateRtpConstructor::AP4_ImmediateRtpConstructor(AP4_ByteStream& stream) : + AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE) +{ + AP4_Position cur_offset; + stream.Tell(cur_offset); + + // data + AP4_UI08 data_size; + stream.ReadUI08(data_size); + m_Data.SetDataSize(data_size); + stream.Read(m_Data.UseData(), data_size); + + // reposition the stream + stream.Seek(cur_offset+15); +} + + +/*---------------------------------------------------------------------- +| AP4_ImmediateRtpConstructor::DoWrite ++---------------------------------------------------------------------*/ +AP4_Result +AP4_ImmediateRtpConstructor::DoWrite(AP4_ByteStream& stream) +{ + // first check that the data is not too large + if (m_Data.GetDataSize() > 14) return AP4_FAILURE; + + // now write + AP4_Result result = stream.WriteUI08(static_cast<AP4_UI08>(m_Data.GetDataSize())); + if (AP4_FAILED(result)) return result; + + result = stream.Write(m_Data.GetData(), m_Data.GetDataSize()); + if (AP4_FAILED(result)) return result; + + // pad + AP4_Byte pad[14]; + return stream.Write(pad, sizeof(pad)-m_Data.GetDataSize()); +} +/*---------------------------------------------------------------------- +| AP4_SampleRtpConstructor::AP4_SampleRtpConstructor ++---------------------------------------------------------------------*/ +AP4_SampleRtpConstructor::AP4_SampleRtpConstructor(AP4_UI08 track_ref_index, + AP4_UI16 length, + AP4_UI32 sample_num, + AP4_UI32 sample_offset) : + AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE), + m_TrackRefIndex(track_ref_index), + m_Length(length), + m_SampleNum(sample_num), + m_SampleOffset(sample_offset) +{} + +/*---------------------------------------------------------------------- +| AP4_SampleRtpConstructor::AP4_SampleRtpConstructor ++---------------------------------------------------------------------*/ +AP4_SampleRtpConstructor::AP4_SampleRtpConstructor(AP4_ByteStream& stream) : + AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE) +{ + // offset + AP4_Position cur_offset; + stream.Tell(cur_offset); + + // data + stream.ReadUI08(m_TrackRefIndex); + stream.ReadUI16(m_Length); + stream.ReadUI32(m_SampleNum); + stream.ReadUI32(m_SampleOffset); + + // reposition the stream + stream.Seek(cur_offset+15); +} +/*---------------------------------------------------------------------- +| AP4_SampleRtpConstructor::DoWrite ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SampleRtpConstructor::DoWrite(AP4_ByteStream& stream) +{ + AP4_Result result = stream.WriteUI08(m_TrackRefIndex); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI16(m_Length); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI32(m_SampleNum); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI32(m_SampleOffset); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI16(1); // bytes per block + if (AP4_FAILED(result)) return result; + + return stream.WriteUI16(1); // samples per block +} + +/*---------------------------------------------------------------------- +| AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor ++---------------------------------------------------------------------*/ +AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor(AP4_UI08 track_ref_index, + AP4_UI16 length, + AP4_UI32 sample_desc_index, + AP4_UI32 sample_desc_offset) : + AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC), + m_TrackRefIndex(track_ref_index), + m_Length(length), + m_SampleDescIndex(sample_desc_index), + m_SampleDescOffset(sample_desc_offset) +{} + +/*---------------------------------------------------------------------- +| AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor ++---------------------------------------------------------------------*/ +AP4_SampleDescRtpConstructor::AP4_SampleDescRtpConstructor(AP4_ByteStream& stream) : + AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC) +{ + // offset + AP4_Position cur_offset; + stream.Tell(cur_offset); + + // data + stream.ReadUI08(m_TrackRefIndex); + stream.ReadUI16(m_Length); + stream.ReadUI32(m_SampleDescIndex); + stream.ReadUI32(m_SampleDescOffset); + + // reposition the stream + stream.Seek(cur_offset+15); +} + +/*---------------------------------------------------------------------- +| AP4_SampleDescRtpConstructor::DoWrite ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SampleDescRtpConstructor::DoWrite(AP4_ByteStream& stream) +{ + AP4_Result result = stream.WriteUI08(m_TrackRefIndex); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI16(m_Length); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI32(m_SampleDescIndex); + if (AP4_FAILED(result)) return result; + + result = stream.WriteUI32(m_SampleDescOffset); + if (AP4_FAILED(result)) return result; + + return stream.WriteUI32(0); // reserved +} + +/*---------------------------------------------------------------------- +| AP4_RtpConstructorFactory::CreateConstructorFromStream ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpConstructorFactory::CreateConstructorFromStream(AP4_ByteStream& stream, + AP4_RtpConstructor*& constructor) +{ + // read the first byte (type) + AP4_RtpConstructor::Type type; + AP4_Result result = stream.ReadUI08(type); + if (AP4_FAILED(result)) return result; + + // now create the right constructor + switch(type) { + case AP4_RTP_CONSTRUCTOR_TYPE_NOOP: + constructor = new AP4_NoopRtpConstructor(stream); + break; + case AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE: + constructor = new AP4_ImmediateRtpConstructor(stream); + break; + case AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE: + constructor = new AP4_SampleRtpConstructor(stream); + break; + case AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC: + constructor = new AP4_SampleDescRtpConstructor(stream); + break; + default: + return AP4_ERROR_INVALID_RTP_CONSTRUCTOR_TYPE; + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpHint.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpHint.h new file mode 100644 index 000000000..f747c8212 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4RtpHint.h @@ -0,0 +1,297 @@ +/***************************************************************** +| +| AP4 - RTP Hint Objects +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_RTP_HINT_H_ +#define _AP4_RTP_HINT_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4DataBuffer.h" +#include "Ap4Interfaces.h" + +/*---------------------------------------------------------------------- +| forward declarations ++---------------------------------------------------------------------*/ +class AP4_ByteStream; +class AP4_RtpConstructor; +class AP4_RtpPacket; + +/*---------------------------------------------------------------------- +| AP4_RtpSampleData ++---------------------------------------------------------------------*/ +class AP4_RtpSampleData +{ +public: + // constructors and destructor + AP4_RtpSampleData(AP4_ByteStream& stream, AP4_UI32 size); + AP4_RtpSampleData() {} + virtual ~AP4_RtpSampleData(); + + // methods + virtual AP4_Result AddPacket(AP4_RtpPacket* packet); + virtual AP4_Size GetSize(); + virtual AP4_ByteStream* ToByteStream(); + + // accessors + AP4_List<AP4_RtpPacket>& GetPackets() { + return m_Packets; + } + const AP4_DataBuffer& GetExtraData() const { + return m_ExtraData; + } + +protected: + // members + AP4_List<AP4_RtpPacket> m_Packets; + AP4_DataBuffer m_ExtraData; +}; + +/*---------------------------------------------------------------------- +| AP4_RtpPacket ++---------------------------------------------------------------------*/ +class AP4_RtpPacket : public AP4_Referenceable +{ +public: + // constructor and destructor + AP4_RtpPacket(AP4_ByteStream& stream); + AP4_RtpPacket(int relative_time, + bool p_bit, + bool x_bit, + bool m_bit, + AP4_UI08 payload_type, + AP4_UI16 sequence_seed, + int time_stamp_offset = 0, + bool bframe_flag = false, + bool repeat_flag = false); + ~AP4_RtpPacket(); + + // methods + AP4_Result Write(AP4_ByteStream& stream); + AP4_Result AddConstructor(AP4_RtpConstructor* constructor); + AP4_Size GetSize(); + AP4_Size GetConstructedDataSize(); + + // Referenceable methods + void AddReference(); + void Release(); + + // Accessors + int GetRelativeTime() const { return m_RelativeTime; } + bool GetPBit() const { return m_PBit; } + bool GetXBit() const { return m_XBit; } + bool GetMBit() const { return m_MBit; } + AP4_UI08 GetPayloadType() const { return m_PayloadType; } + AP4_UI16 GetSequenceSeed() const { return m_SequenceSeed; } + int GetTimeStampOffset() const { return m_TimeStampOffset; } + bool GetBFrameFlag() const { return m_BFrameFlag; } + bool GetRepeatFlag() const { return m_RepeatFlag; } + AP4_List<AP4_RtpConstructor>& GetConstructors() { + return m_Constructors; + } + +private: + // members + AP4_Cardinal m_ReferenceCount; + int m_RelativeTime; + bool m_PBit; + bool m_XBit; + bool m_MBit; + AP4_UI08 m_PayloadType; + AP4_UI16 m_SequenceSeed; + int m_TimeStampOffset; + bool m_BFrameFlag; + bool m_RepeatFlag; + AP4_List<AP4_RtpConstructor> m_Constructors; +}; + +/*---------------------------------------------------------------------- +| AP4_RtpContructor ++---------------------------------------------------------------------*/ +class AP4_RtpConstructor : public AP4_Referenceable +{ +public: + // types + typedef AP4_UI08 Type; + + // constructor & destructor + AP4_RtpConstructor(Type type) : m_ReferenceCount(1), m_Type(type) {} + + // methods + Type GetType() const { return m_Type; } + AP4_Result Write(AP4_ByteStream& stream); + virtual AP4_Size GetConstructedDataSize() = 0; + + // Referenceable methods + void AddReference(); + void Release(); + +protected: + // methods + virtual ~AP4_RtpConstructor() {} + virtual AP4_Result DoWrite(AP4_ByteStream& stream) = 0; + + // members + AP4_Cardinal m_ReferenceCount; + Type m_Type; +}; + +/*---------------------------------------------------------------------- +| constructor size ++---------------------------------------------------------------------*/ +const AP4_Size AP4_RTP_CONSTRUCTOR_SIZE = 16; + +/*---------------------------------------------------------------------- +| constructor types ++---------------------------------------------------------------------*/ +const AP4_RtpConstructor::Type AP4_RTP_CONSTRUCTOR_TYPE_NOOP = 0; +const AP4_RtpConstructor::Type AP4_RTP_CONSTRUCTOR_TYPE_IMMEDIATE = 1; +const AP4_RtpConstructor::Type AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE = 2; +const AP4_RtpConstructor::Type AP4_RTP_CONSTRUCTOR_TYPE_SAMPLE_DESC = 3; + +/*---------------------------------------------------------------------- +| AP4_NoopRtpConstructor ++---------------------------------------------------------------------*/ +class AP4_NoopRtpConstructor : public AP4_RtpConstructor +{ +public: + // constructor + AP4_NoopRtpConstructor(AP4_ByteStream& stream); + AP4_NoopRtpConstructor() : AP4_RtpConstructor(AP4_RTP_CONSTRUCTOR_TYPE_NOOP) {} + + // methods + virtual AP4_Size GetConstructedDataSize() { return 0; } + +protected: + // methods + virtual AP4_Result DoWrite(AP4_ByteStream& stream); +}; + +/*---------------------------------------------------------------------- +| AP4_ImmediateRtpConstructor ++---------------------------------------------------------------------*/ +class AP4_ImmediateRtpConstructor : public AP4_RtpConstructor +{ +public: + // constructor + AP4_ImmediateRtpConstructor(AP4_ByteStream& stream); + AP4_ImmediateRtpConstructor(const AP4_DataBuffer& data); + + // accessors + const AP4_DataBuffer& GetData() const { return m_Data; } + + // methods + virtual AP4_Size GetConstructedDataSize() { return m_Data.GetDataSize(); } + +protected: + // methods + virtual AP4_Result DoWrite(AP4_ByteStream& stream); + + // members + AP4_DataBuffer m_Data; +}; + +/*---------------------------------------------------------------------- +| AP4_SampleRtpConstructor ++---------------------------------------------------------------------*/ +class AP4_SampleRtpConstructor : public AP4_RtpConstructor +{ +public: + // constructor + AP4_SampleRtpConstructor(AP4_ByteStream& stream); + AP4_SampleRtpConstructor(AP4_UI08 track_ref_index, + AP4_UI16 length, + AP4_UI32 sample_num, + AP4_UI32 sample_offset); + + // accessors + AP4_UI08 GetTrackRefIndex() const { return m_TrackRefIndex; } + AP4_UI16 GetLength() const { return m_Length; } + AP4_UI32 GetSampleNum() const { return m_SampleNum; } + AP4_UI32 GetSampleOffset() const { return m_SampleOffset; } + + // methods + virtual AP4_Size GetConstructedDataSize() { return m_Length; } + +protected: + // methods + virtual AP4_Result DoWrite(AP4_ByteStream& stream); + + // members + AP4_UI08 m_TrackRefIndex; + AP4_UI16 m_Length; + AP4_UI32 m_SampleNum; + AP4_UI32 m_SampleOffset; +}; + +/*---------------------------------------------------------------------- +| AP4_SampleDescRtpConstructor ++---------------------------------------------------------------------*/ +class AP4_SampleDescRtpConstructor : public AP4_RtpConstructor +{ +public: + // constructor + AP4_SampleDescRtpConstructor(AP4_ByteStream& stream); + AP4_SampleDescRtpConstructor(AP4_UI08 track_ref_index, + AP4_UI16 length, + AP4_UI32 sample_desc_index, + AP4_UI32 sample_desc_offset); + + // accessors + AP4_UI08 GetTrackRefIndex() const { return m_TrackRefIndex; } + AP4_UI16 GetLength() const { return m_Length; } + AP4_UI32 GetSampleDescIndex() const { return m_SampleDescIndex; } + AP4_UI32 GetSampleDescOffset() const { return m_SampleDescOffset; } + + // methods + virtual AP4_Size GetConstructedDataSize() { return m_Length; } + +protected: + // methods + virtual AP4_Result DoWrite(AP4_ByteStream& stream); + + // members + AP4_UI08 m_TrackRefIndex; + AP4_UI16 m_Length; + AP4_UI32 m_SampleDescIndex; + AP4_UI32 m_SampleDescOffset; +}; + +/*---------------------------------------------------------------------- +| AP4_RtpConstructorFactory ++---------------------------------------------------------------------*/ +class AP4_RtpConstructorFactory +{ +public: + static AP4_Result CreateConstructorFromStream(AP4_ByteStream& stream, + AP4_RtpConstructor*& constructor); +}; + +#endif // _AP4_RTP_HINT_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SLConfigDescriptor.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SLConfigDescriptor.cpp new file mode 100644 index 000000000..7b791c3e4 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SLConfigDescriptor.cpp @@ -0,0 +1,54 @@ +/***************************************************************** +| +| AP4 - SLConfig Descriptor +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SLConfigDescriptor.h" +#include "Ap4ByteStream.h" + +/*---------------------------------------------------------------------- +| AP4_SLConfigDescriptor::AP4_SLConfigDescriptor ++---------------------------------------------------------------------*/ +AP4_SLConfigDescriptor::AP4_SLConfigDescriptor(AP4_Size header_size) : + AP4_Descriptor(AP4_DESCRIPTOR_TAG_SL_CONFIG, header_size, 1), + m_Predefined(2) +{ +} + +/*---------------------------------------------------------------------- +| AP4_SLConfigDescriptor::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SLConfigDescriptor::WriteFields(AP4_ByteStream& stream) +{ + // write the payload + stream.WriteUI08(m_Predefined); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SLConfigDescriptor.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SLConfigDescriptor.h new file mode 100644 index 000000000..73a26ec9b --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SLConfigDescriptor.h @@ -0,0 +1,59 @@ +/***************************************************************** +| +| AP4 - SLConfig Descriptor +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_SLCONFIG_DESCRIPTOR_H_ +#define _AP4_SLCONFIG_DESCRIPTOR_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Descriptor.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI08 AP4_DESCRIPTOR_TAG_SL_CONFIG = 0x06; + +/*---------------------------------------------------------------------- +| AP4_SLConfigDescriptor ++---------------------------------------------------------------------*/ +class AP4_SLConfigDescriptor : public AP4_Descriptor +{ +public: + // methods + AP4_SLConfigDescriptor(AP4_Size header_size = 2); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // members + AP4_UI08 m_Predefined; // = 2 (fixed for MP4 files) +}; + + +#endif // _AP4_SLCONFIG_DESCRIPTOR_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Sample.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Sample.cpp new file mode 100644 index 000000000..060084044 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Sample.cpp @@ -0,0 +1,175 @@ +/***************************************************************** +| +| AP4 - Sample Objects +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Sample.h" +#include "Ap4Utils.h" +#include "Ap4DataBuffer.h" +#include "Ap4Interfaces.h" +#include "Ap4ByteStream.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_Sample::AP4_Sample ++---------------------------------------------------------------------*/ +AP4_Sample::AP4_Sample() : + m_DataStream(NULL), + m_Offset(0), + m_Size(0), + m_Duration(0), + m_DescriptionIndex(0), + m_Dts(0), + m_CtsDelta(0), + m_IsSync(true) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Sample::AP4_Sample ++---------------------------------------------------------------------*/ +AP4_Sample::AP4_Sample(AP4_ByteStream& data_stream, + AP4_Position offset, + AP4_Size size, + AP4_UI32 duration, + AP4_Ordinal description_index, + AP4_UI64 dts, + AP4_UI32 cts_delta, + bool is_sync) : + m_Offset(offset), + m_Size(size), + m_Duration(duration), + m_DescriptionIndex(description_index), + m_Dts(dts), + m_CtsDelta(cts_delta), + m_IsSync(is_sync) +{ + m_DataStream = &data_stream; + AP4_ADD_REFERENCE(m_DataStream); +} + +/*---------------------------------------------------------------------- +| AP4_Sample::AP4_Sample ++---------------------------------------------------------------------*/ +AP4_Sample::AP4_Sample(const AP4_Sample& other) : + m_DataStream(other.m_DataStream), + m_Offset(other.m_Offset), + m_Size(other.m_Size), + m_Duration(other.m_Duration), + m_DescriptionIndex(other.m_DescriptionIndex), + m_Dts(other.m_Dts), + m_CtsDelta(other.m_CtsDelta), + m_IsSync(other.m_IsSync) +{ + AP4_ADD_REFERENCE(m_DataStream); +} + +/*---------------------------------------------------------------------- +| AP4_Sample::~AP4_Sample ++---------------------------------------------------------------------*/ +AP4_Sample::~AP4_Sample() +{ + AP4_RELEASE(m_DataStream); +} + +/*---------------------------------------------------------------------- +| AP4_Sample::operator= ++---------------------------------------------------------------------*/ +AP4_Sample& +AP4_Sample::operator=(const AP4_Sample& other) +{ + AP4_ADD_REFERENCE(other.m_DataStream); + AP4_RELEASE(m_DataStream); + m_DataStream = other.m_DataStream; + + m_Offset = other.m_Offset; + m_Size = other.m_Size; + m_Duration = other.m_Duration; + m_DescriptionIndex = other.m_DescriptionIndex; + m_Dts = other.m_Dts; + m_CtsDelta = other.m_CtsDelta; + m_IsSync = other.m_IsSync; + + return *this; +} +/*---------------------------------------------------------------------- +| AP4_Sample::ReadData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Sample::ReadData(AP4_DataBuffer& data) +{ + return ReadData(data, m_Size); +} + + +/*---------------------------------------------------------------------- +| AP4_Sample::ReadData ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Sample::ReadData(AP4_DataBuffer& data, AP4_Size size, AP4_Size offset) +{ + // check that we have a stream + if (m_DataStream == NULL) return AP4_FAILURE; + + // shortcut + if (size == 0) return AP4_SUCCESS; + + // check the size + if (m_Size < size+offset) return AP4_FAILURE; + + // set the buffer size + AP4_Result result = data.SetDataSize(size); + if (AP4_FAILED(result)) return result; + + // get the data from the stream + result = m_DataStream->Seek(m_Offset+offset); + if (AP4_FAILED(result)) return result; + return m_DataStream->Read(data.UseData(), size); +} + +/*---------------------------------------------------------------------- +| AP4_Sample::GetDataStream ++---------------------------------------------------------------------*/ +AP4_ByteStream* +AP4_Sample::GetDataStream() +{ + AP4_ADD_REFERENCE(m_DataStream); + return m_DataStream; +} + +/*---------------------------------------------------------------------- +| AP4_Sample::SetDataStream ++---------------------------------------------------------------------*/ +void +AP4_Sample::SetDataStream(AP4_ByteStream& stream) +{ + AP4_RELEASE(m_DataStream); + m_DataStream = &stream; + AP4_ADD_REFERENCE(m_DataStream); +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Sample.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Sample.h new file mode 100644 index 000000000..ba5a0235f --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Sample.h @@ -0,0 +1,168 @@ +/*****************************************************************
+|
+| AP4 - Sample Objects
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_SAMPLE_H_
+#define _AP4_SAMPLE_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+
+/*----------------------------------------------------------------------
+| class references
++---------------------------------------------------------------------*/
+class AP4_ByteStream;
+class AP4_DataBuffer;
+
+/*----------------------------------------------------------------------
+| AP4_Sample DO NOT DERIVE FROM THIS CLASS
++---------------------------------------------------------------------*/
+class AP4_Sample
+{
+public:
+ /**
+ * Default constructor
+ */
+ AP4_Sample();
+
+ /**
+ * Copy constructor
+ */
+ AP4_Sample(const AP4_Sample& other);
+
+ /**
+ * Construct an AP4_Sample referencing a data stream
+ *
+ * @param data_stream The byte stream that contains the sample data.
+ * The sample object added to the track will keep a reference to that byte
+ * stream
+ * @param offset Position of the first byte of sample data within the stream
+ * @param size Size in bytes of the sample data
+ * @param description_index Index of the sample description that applies to
+ * this sample
+ * @param dts Decoding timestamp of the sample
+ * @param cts_delta Difference between the CTS (composition/display timestamp) and the
+ * DTS (decoding timestamp), in the timescale of the media.
+ * @param sync_flag Boolean flag indicating whether this is a sync sample
+ * or not
+ */
+ AP4_Sample(AP4_ByteStream& data_stream,
+ AP4_Position offset,
+ AP4_Size size,
+ AP4_UI32 duration,
+ AP4_Ordinal description_index,
+ AP4_UI64 dts,
+ AP4_UI32 cts_delta,
+ bool sync_flag);
+
+ ~AP4_Sample(); // not virtual on purpose: do not derive from it
+
+ // operators
+ AP4_Sample& operator=(const AP4_Sample& other);
+
+ // methods
+ AP4_Result ReadData(AP4_DataBuffer& data);
+ AP4_Result ReadData(AP4_DataBuffer& data,
+ AP4_Size size,
+ AP4_Size offset = 0);
+
+ // sample properties accessors
+ AP4_ByteStream* GetDataStream();
+ void SetDataStream(AP4_ByteStream& stream);
+ AP4_Position GetOffset() const { return m_Offset; }
+ void SetOffset(AP4_Position offset) { m_Offset = offset; }
+ AP4_Size GetSize() { return m_Size; }
+ void SetSize(AP4_Size size) { m_Size = size; }
+ AP4_Ordinal GetDescriptionIndex() const { return m_DescriptionIndex; }
+ void SetDescriptionIndex(AP4_Ordinal index) { m_DescriptionIndex = index; }
+
+ /**
+ * Get the DTS (Decoding Time Stamp) of the sample in the timescale of the media
+ */
+ AP4_UI64 GetDts() const { return m_Dts; }
+
+ /**
+ * Set the DTS (Decoding Time Stamp) of the sample in the timescale of the media
+ */
+ void SetDts(AP4_UI64 dts) { m_Dts = dts; }
+
+ /**
+ * Get the CTS (Composition Time Stamp) of the sample in the timescale of the media
+ */
+ AP4_UI64 GetCts() const { return m_Dts+m_CtsDelta; }
+
+ /**
+ * Set the CTS (Composition Time Stamp) of the sample in the timescale of the media
+ */
+ void SetCts(AP4_UI64 cts) { m_CtsDelta = (cts > m_Dts) ? (AP4_UI32)(cts-m_Dts) : 0; }
+
+ /**
+ * Get the CTS Delta (difference between the CTS (Composition Time Stamp) and DTS (Decoding Time Stamp)
+ * of the sample in the timescale of the media.
+ */
+ AP4_UI32 GetCtsDelta() const { return m_CtsDelta; }
+
+ /**
+ * Set the CTS Delta (difference between the CTS (Composition Time Stamp) and DTS (Decoding Time Stamp)
+ * of the sample in the timescale of the media.
+ */
+ void SetCtsDelta(AP4_UI32 delta) { m_CtsDelta = (AP4_SI32)delta; }
+
+ /**
+ * Get the duration of the sample in the timescale of the media
+ */
+ AP4_UI32 GetDuration() const { return m_Duration; }
+
+ /**
+ * Set the duration of the sample in the timescale of the media
+ */
+ void SetDuration(AP4_UI32 duration) { m_Duration = duration; }
+
+ /**
+ * Return whether the sample is a sync (random-access point) sample or not.
+ */
+ bool IsSync() const { return m_IsSync; }
+
+ /**
+ * Set whether the sample is a sync (random-access point) sample or not.
+ */
+ void SetSync(bool is_sync) { m_IsSync = is_sync; }
+
+protected:
+ AP4_ByteStream* m_DataStream;
+ AP4_Position m_Offset;
+ AP4_Size m_Size;
+ AP4_UI32 m_Duration;
+ AP4_Ordinal m_DescriptionIndex;
+ AP4_UI64 m_Dts;
+ AP4_SI32 m_CtsDelta; // make this a signed value, because quicktime can use negative offsets
+ bool m_IsSync;
+};
+
+#endif // _AP4_SAMPLE_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleDescription.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleDescription.cpp new file mode 100644 index 000000000..e301d0cf4 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleDescription.cpp @@ -0,0 +1,618 @@ +/*****************************************************************
+|
+| AP4 - Sample Description Objects
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4SampleDescription.h"
+#include "Ap4EsDescriptor.h"
+#include "Ap4SLConfigDescriptor.h"
+#include "Ap4SampleEntry.h"
+#include "Ap4AvccAtom.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_SampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_UnknownSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_AudioSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_VideoSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_GenericAudioSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_GenericVideoSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MpegSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MpegAudioSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MpegVideoSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_MpegSystemSampleDescription)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_AvcSampleDescription)
+
+/*----------------------------------------------------------------------
+| AP4_GetFormatName
++---------------------------------------------------------------------*/
+const char*
+AP4_GetFormatName(AP4_UI32 format)
+{
+ switch (format) {
+ case AP4_SAMPLE_FORMAT_MP4A: return "MPEG-4 Audio";
+ case AP4_SAMPLE_FORMAT_MP4V: return "MPEG-4 Video";
+ case AP4_SAMPLE_FORMAT_MP4S: return "MPEG-4 Systems";
+ case AP4_SAMPLE_FORMAT_ALAC: return "Apple Lossless Audio";
+ case AP4_SAMPLE_FORMAT_AVC1: return "H.264";
+ case AP4_SAMPLE_FORMAT_OVC1: return "VC-1";
+ case AP4_SAMPLE_FORMAT_OWMA: return "WMA";
+ case AP4_SAMPLE_FORMAT_AC_3: return "Dolby Digital (AC-3)";
+ case AP4_SAMPLE_FORMAT_EC_3: return "Dolby Digital Plus (Enhanced AC-3)";
+ case AP4_SAMPLE_FORMAT_AVCP: return "Advanced Video Coding Parameters";
+ case AP4_SAMPLE_FORMAT_DRAC: return "Dirac";
+ case AP4_SAMPLE_FORMAT_DRA1: return "DRA Audio";
+ case AP4_SAMPLE_FORMAT_G726: return "G726";
+ case AP4_SAMPLE_FORMAT_MJP2: return "Motion JPEG 2000";
+ case AP4_SAMPLE_FORMAT_OKSD: return "OMA Keys";
+ case AP4_SAMPLE_FORMAT_RAW_: return "Uncompressed Audio";
+ case AP4_SAMPLE_FORMAT_RTP_: return "RTP Hints";
+ case AP4_SAMPLE_FORMAT_S263: return "H.263";
+ case AP4_SAMPLE_FORMAT_SAMR: return "Narrowband AMR";
+ case AP4_SAMPLE_FORMAT_SAWB: return "Wideband AMR";
+ case AP4_SAMPLE_FORMAT_SAWP: return "Extended AMR";
+ case AP4_SAMPLE_FORMAT_SEVC: return "EVRC Voice";
+ case AP4_SAMPLE_FORMAT_SQCP: return "13K Voice";
+ case AP4_SAMPLE_FORMAT_SRTP: return "SRTP Hints";
+ case AP4_SAMPLE_FORMAT_SSMV: return "SMV Voice";
+ case AP4_SAMPLE_FORMAT_TEXT: return "Textual Metadata";
+ case AP4_SAMPLE_FORMAT_TWOS: return "Uncompressed 16-bit Audio";
+ case AP4_SAMPLE_FORMAT_TX3G: return "Timed Text";
+ case AP4_SAMPLE_FORMAT_VC_1: return "SMPTE VC-1";
+ case AP4_SAMPLE_FORMAT_XML_: return "XML Metadata";
+ default: return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_SampleDescription::AP4_SampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription::AP4_SampleDescription(Type type,
+ AP4_UI32 format,
+ AP4_AtomParent* details) :
+ m_Type(type), m_Format(format)
+{
+ if (details) {
+ for (AP4_List<AP4_Atom>::Item* item = details->GetChildren().FirstItem();
+ item;
+ item = item->GetNext()) {
+ AP4_Atom* atom = item->GetData();
+ if (atom) {
+ AP4_Atom* clone = atom->Clone();
+ if (clone) m_Details.AddChild(clone);
+ }
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_SampleDescription::Clone
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_SampleDescription::Clone(AP4_Result* result)
+{
+ if (result) *result = AP4_SUCCESS;
+ AP4_Atom* atom = ToAtom();
+ if (atom == NULL) {
+ if (result) *result = AP4_FAILURE;
+ return NULL;
+ }
+ AP4_SampleEntry* sample_entry = AP4_DYNAMIC_CAST(AP4_SampleEntry, atom);
+ if (sample_entry == NULL) {
+ if (result) *result = AP4_ERROR_INTERNAL;
+ delete atom;
+ return NULL;
+ }
+
+ AP4_SampleDescription* clone = sample_entry->ToSampleDescription();
+ if (clone == NULL) {
+ if (result) *result = AP4_ERROR_INTERNAL;
+ }
+
+ delete atom;
+ return clone;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SampleDescription::ToAtom
++---------------------------------------------------------------------*/
+AP4_Atom*
+AP4_SampleDescription::ToAtom() const
+{
+ return new AP4_SampleEntry(m_Format);
+}
+
+/*----------------------------------------------------------------------
+| AP4_UnknownSampleDescription::AP4_UnknownSampleDescription
++---------------------------------------------------------------------*/
+AP4_UnknownSampleDescription::AP4_UnknownSampleDescription(AP4_Atom* atom) :
+ AP4_SampleDescription(AP4_SampleDescription::TYPE_UNKNOWN,
+ atom->GetType(),
+ NULL),
+ m_Atom(atom->Clone())
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_UnknownSampleDescription::~AP4_UnknownSampleDescription
++---------------------------------------------------------------------*/
+AP4_UnknownSampleDescription::~AP4_UnknownSampleDescription()
+{
+ delete m_Atom;
+}
+
+/*----------------------------------------------------------------------
+| AP4_UnknownSampleDescription::Clone
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_UnknownSampleDescription::Clone(AP4_Result* result)
+{
+ AP4_Atom* atom_clone = NULL;
+ if (m_Atom) {
+ atom_clone = m_Atom->Clone();
+ if (atom_clone == NULL) {
+ if (result) *result = AP4_FAILURE;
+ return NULL;
+ }
+ }
+ if (result) *result = AP4_SUCCESS;
+ return new AP4_UnknownSampleDescription(atom_clone);
+}
+
+/*----------------------------------------------------------------------
+| AP4_UnknownSampleDescription::ToAtom
++---------------------------------------------------------------------*/
+AP4_Atom*
+AP4_UnknownSampleDescription::ToAtom() const
+{
+ if (m_Atom) {
+ return m_Atom->Clone();
+ } else {
+ return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvcSampleDescription::AP4_AvcSampleDescription
++---------------------------------------------------------------------*/
+AP4_AvcSampleDescription::AP4_AvcSampleDescription(AP4_UI16 width,
+ AP4_UI16 height,
+ AP4_UI16 depth,
+ const char* compressor_name,
+ AP4_UI08 profile,
+ AP4_UI08 level,
+ AP4_UI08 profile_compatibility,
+ AP4_UI08 length_size,
+ const AP4_Array<AP4_DataBuffer>& sequence_parameters,
+ const AP4_Array<AP4_DataBuffer>& picture_parameters) :
+ AP4_SampleDescription(TYPE_AVC, AP4_SAMPLE_FORMAT_AVC1, NULL),
+ AP4_VideoSampleDescription(width, height, depth, compressor_name)
+{
+ m_AvccAtom = new AP4_AvccAtom(profile,
+ level,
+ profile_compatibility,
+ length_size,
+ sequence_parameters,
+ picture_parameters);
+ m_Details.AddChild(m_AvccAtom);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvcSampleDescription::AP4_AvcSampleDescription
++---------------------------------------------------------------------*/
+AP4_AvcSampleDescription::AP4_AvcSampleDescription(AP4_UI16 width,
+ AP4_UI16 height,
+ AP4_UI16 depth,
+ const char* compressor_name,
+ const AP4_AvccAtom* avcc) :
+ AP4_SampleDescription(TYPE_AVC, AP4_SAMPLE_FORMAT_AVC1, NULL),
+ AP4_VideoSampleDescription(width, height, depth, compressor_name)
+{
+ if (avcc) {
+ m_AvccAtom = new AP4_AvccAtom(*avcc);
+ } else {
+ // should never happen
+ m_AvccAtom = new AP4_AvccAtom();
+ }
+ m_Details.AddChild(m_AvccAtom);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvcSampleDescription::AP4_AvcSampleDescription
++---------------------------------------------------------------------*/
+AP4_AvcSampleDescription::AP4_AvcSampleDescription(AP4_UI16 width,
+ AP4_UI16 height,
+ AP4_UI16 depth,
+ const char* compressor_name,
+ AP4_AtomParent* details) :
+ AP4_SampleDescription(TYPE_AVC, AP4_SAMPLE_FORMAT_AVC1, details),
+ AP4_VideoSampleDescription(width, height, depth, compressor_name),
+ m_AvccAtom(NULL)
+{
+ AP4_AvccAtom* avcc = AP4_DYNAMIC_CAST(AP4_AvccAtom, details->GetChild(AP4_ATOM_TYPE_AVCC));
+ if (avcc) {
+ m_AvccAtom = new AP4_AvccAtom(*avcc);
+ } else {
+ // shoud never happen
+ m_AvccAtom = new AP4_AvccAtom();
+ }
+ m_Details.AddChild(m_AvccAtom);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AvcSampleDescription::ToAtom
++---------------------------------------------------------------------*/
+AP4_Atom*
+AP4_AvcSampleDescription::ToAtom() const
+{
+ return new AP4_Avc1SampleEntry(m_Width,
+ m_Height,
+ m_Depth,
+ m_CompressorName.GetChars(),
+ *m_AvccAtom);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSampleDescription::AP4_MpegSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegSampleDescription::AP4_MpegSampleDescription(AP4_UI32 format,
+ AP4_EsdsAtom* esds) :
+ AP4_SampleDescription(TYPE_MPEG, format, NULL),
+ m_StreamType(0),
+ m_ObjectTypeId(0),
+ m_BufferSize(0),
+ m_MaxBitrate(0),
+ m_AvgBitrate(0)
+{
+ if (esds) {
+ // get the es descriptor
+ const AP4_EsDescriptor* es_desc = esds->GetEsDescriptor();
+ if (es_desc == NULL) return;
+
+ // get the decoder config descriptor
+ const AP4_DecoderConfigDescriptor* dc_desc =
+ es_desc->GetDecoderConfigDescriptor();
+ if (dc_desc) {
+ m_StreamType = dc_desc->GetStreamType();
+ m_ObjectTypeId = dc_desc->GetObjectTypeIndication();
+ m_BufferSize = dc_desc->GetBufferSize();
+ m_MaxBitrate = dc_desc->GetMaxBitrate();
+ m_AvgBitrate = dc_desc->GetAvgBitrate();
+ const AP4_DecoderSpecificInfoDescriptor* dsi_desc =
+ dc_desc->GetDecoderSpecificInfoDescriptor();
+ if (dsi_desc != NULL) {
+ m_DecoderInfo.SetData(dsi_desc->GetDecoderSpecificInfo().GetData(),
+ dsi_desc->GetDecoderSpecificInfo().GetDataSize());
+ }
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSampleDescription::AP4_MpegSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegSampleDescription::AP4_MpegSampleDescription(
+ AP4_UI32 format,
+ StreamType stream_type,
+ OTI oti,
+ const AP4_DataBuffer* decoder_info,
+ AP4_UI32 buffer_size,
+ AP4_UI32 max_bitrate,
+ AP4_UI32 avg_bitrate) :
+ AP4_SampleDescription(TYPE_MPEG, format, NULL),
+ m_StreamType(stream_type),
+ m_ObjectTypeId(oti),
+ m_BufferSize(buffer_size),
+ m_MaxBitrate(max_bitrate),
+ m_AvgBitrate(avg_bitrate)
+{
+ if (decoder_info != NULL) {
+ m_DecoderInfo.SetData(decoder_info->GetData(), decoder_info->GetDataSize());
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSampleDescription::CreateEsDescriptor
++---------------------------------------------------------------------*/
+AP4_EsDescriptor*
+AP4_MpegSampleDescription::CreateEsDescriptor() const
+{
+ AP4_EsDescriptor* desc = new AP4_EsDescriptor(0);
+ AP4_DecoderSpecificInfoDescriptor* dsi_desc;
+ if (m_DecoderInfo.GetDataSize() != 0) {
+ dsi_desc = new AP4_DecoderSpecificInfoDescriptor(m_DecoderInfo);
+ } else {
+ dsi_desc = NULL;
+ }
+ AP4_DecoderConfigDescriptor* decoder_config =
+ new AP4_DecoderConfigDescriptor(m_StreamType,
+ m_ObjectTypeId,
+ m_BufferSize,
+ m_MaxBitrate,
+ m_AvgBitrate,
+ dsi_desc);
+ desc->AddSubDescriptor(decoder_config);
+
+ // add a fixed SL Config
+ desc->AddSubDescriptor(new AP4_SLConfigDescriptor());
+
+ return desc;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSystemSampleDescription::AP4_MpegSystemSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegSystemSampleDescription::AP4_MpegSystemSampleDescription(AP4_EsdsAtom* esds) :
+ AP4_MpegSampleDescription(AP4_ATOM_TYPE_MP4S, esds)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSystemSampleDescription::AP4_MpegSystemSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegSystemSampleDescription::AP4_MpegSystemSampleDescription(
+ StreamType stream_type,
+ OTI oti,
+ const AP4_DataBuffer* decoder_info,
+ AP4_UI32 buffer_size,
+ AP4_UI32 max_bitrate,
+ AP4_UI32 avg_bitrate) :
+ AP4_MpegSampleDescription(AP4_ATOM_TYPE_MP4S,
+ stream_type,
+ oti,
+ decoder_info,
+ buffer_size,
+ max_bitrate,
+ avg_bitrate)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSystemSampleDescription::ToAtom
++---------------------------------------------------------------------*/
+AP4_Atom*
+AP4_MpegSystemSampleDescription::ToAtom() const
+{
+ return new AP4_Mp4sSampleEntry(CreateEsDescriptor());
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegAudioSampleDescription::AP4_MpegAudioSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegAudioSampleDescription::AP4_MpegAudioSampleDescription(
+ unsigned int sample_rate,
+ unsigned int sample_size,
+ unsigned int channel_count,
+ AP4_EsdsAtom* esds) :
+ AP4_MpegSampleDescription(AP4_ATOM_TYPE_MP4A, esds),
+ AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegAudioSampleDescription::AP4_MpegAudioSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegAudioSampleDescription::AP4_MpegAudioSampleDescription(
+ OTI oti,
+ unsigned int sample_rate,
+ unsigned int sample_size,
+ unsigned int channel_count,
+ const AP4_DataBuffer* decoder_info,
+ AP4_UI32 buffer_size,
+ AP4_UI32 max_bitrate,
+ AP4_UI32 avg_bitrate) :
+ AP4_MpegSampleDescription(AP4_ATOM_TYPE_MP4A,
+ AP4_STREAM_TYPE_AUDIO,
+ oti,
+ decoder_info, buffer_size,
+ max_bitrate, avg_bitrate),
+ AP4_AudioSampleDescription(sample_rate, sample_size, channel_count)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegAudioSampleDescription::ToAtom
++---------------------------------------------------------------------*/
+AP4_Atom*
+AP4_MpegAudioSampleDescription::ToAtom() const
+{
+ return new AP4_Mp4aSampleEntry(m_SampleRate<<16,
+ m_SampleSize,
+ m_ChannelCount,
+ CreateEsDescriptor());
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegAudioSampleDescription::GetMpeg4AudioObjectType
++---------------------------------------------------------------------*/
+AP4_MpegAudioSampleDescription::Mpeg4AudioObjectType
+AP4_MpegAudioSampleDescription::GetMpeg4AudioObjectType() const
+{
+ if (m_ObjectTypeId == AP4_OTI_MPEG4_AUDIO &&
+ m_DecoderInfo.GetDataSize() >= 1) {
+ AP4_UI08 type = m_DecoderInfo.GetData()[0]>>3;
+ if (type == 31) {
+ if (m_DecoderInfo.GetDataSize() < 2) return 0;
+ type = 32+(((m_DecoderInfo.GetData()[0]&0x07)<<3) |
+ ((m_DecoderInfo.GetData()[1]&0xE0)>>5));
+ }
+ return type;
+ } else {
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegVideoSampleDescription::AP4_MpegVideoSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegVideoSampleDescription::AP4_MpegVideoSampleDescription(
+ AP4_UI16 width,
+ AP4_UI16 height,
+ AP4_UI16 depth,
+ const char* compressor_name,
+ AP4_EsdsAtom* esds) :
+
+ AP4_MpegSampleDescription(AP4_ATOM_TYPE_MP4V, esds),
+ AP4_VideoSampleDescription(width, height, depth, compressor_name)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegVideoSampleDescription::AP4_MpegVideoSampleDescription
++---------------------------------------------------------------------*/
+AP4_MpegVideoSampleDescription::AP4_MpegVideoSampleDescription(
+ OTI oti,
+ AP4_UI16 width,
+ AP4_UI16 height,
+ AP4_UI16 depth,
+ const char* compressor_name,
+ const AP4_DataBuffer* decoder_info,
+ AP4_UI32 buffer_size,
+ AP4_UI32 max_bitrate,
+ AP4_UI32 avg_bitrate) :
+ AP4_MpegSampleDescription(AP4_ATOM_TYPE_MP4V,
+ AP4_STREAM_TYPE_VISUAL,
+ oti,
+ decoder_info,
+ buffer_size,
+ max_bitrate,
+ avg_bitrate),
+ AP4_VideoSampleDescription(width, height, depth, compressor_name)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegVideoSampleDescription::ToAtom
++---------------------------------------------------------------------*/
+AP4_Atom*
+AP4_MpegVideoSampleDescription::ToAtom() const
+{
+ return new AP4_Mp4vSampleEntry(m_Width,
+ m_Height,
+ m_Depth,
+ m_CompressorName.GetChars(),
+ CreateEsDescriptor());
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSampleDescription::GetStreamTypeString
++---------------------------------------------------------------------*/
+const char*
+AP4_MpegSampleDescription::GetStreamTypeString(StreamType type)
+{
+ switch (type) {
+ case AP4_STREAM_TYPE_FORBIDDEN: return "INVALID";
+ case AP4_STREAM_TYPE_OD: return "Object Descriptor";
+ case AP4_STREAM_TYPE_CR: return "CR";
+ case AP4_STREAM_TYPE_BIFS: return "BIFS";
+ case AP4_STREAM_TYPE_VISUAL: return "Visual";
+ case AP4_STREAM_TYPE_AUDIO: return "Audio";
+ case AP4_STREAM_TYPE_MPEG7: return "MPEG-7";
+ case AP4_STREAM_TYPE_IPMP: return "IPMP";
+ case AP4_STREAM_TYPE_OCI: return "OCI";
+ case AP4_STREAM_TYPE_MPEGJ: return "MPEG-J";
+ default: return "UNKNOWN";
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegSampleDescription::GetObjectTypeString
++---------------------------------------------------------------------*/
+const char*
+AP4_MpegSampleDescription::GetObjectTypeString(OTI oti)
+{
+ switch (oti) {
+ case AP4_OTI_MPEG4_SYSTEM: return "MPEG-4 System";
+ case AP4_OTI_MPEG4_SYSTEM_COR: return "MPEG-4 System COR";
+ case AP4_OTI_MPEG4_VISUAL: return "MPEG-4 Video";
+ case AP4_OTI_MPEG4_AUDIO: return "MPEG-4 Audio";
+ case AP4_OTI_MPEG2_VISUAL_SIMPLE: return "MPEG-2 Video Simple Profile";
+ case AP4_OTI_MPEG2_VISUAL_MAIN: return "MPEG-2 Video Main Profile";
+ case AP4_OTI_MPEG2_VISUAL_SNR: return "MPEG-2 Video SNR";
+ case AP4_OTI_MPEG2_VISUAL_SPATIAL: return "MPEG-2 Video Spatial";
+ case AP4_OTI_MPEG2_VISUAL_HIGH: return "MPEG-2 Video High";
+ case AP4_OTI_MPEG2_VISUAL_422: return "MPEG-2 Video 4:2:2";
+ case AP4_OTI_MPEG2_AAC_AUDIO_MAIN: return "MPEG-2 Audio AAC Main Profile";
+ case AP4_OTI_MPEG2_AAC_AUDIO_LC: return "MPEG-2 Audio AAC Low Complexity";
+ case AP4_OTI_MPEG2_AAC_AUDIO_SSRP: return "MPEG-2 Audio AAC SSRP";
+ case AP4_OTI_MPEG2_PART3_AUDIO: return "MPEG-2 Audio Part-3";
+ case AP4_OTI_MPEG1_VISUAL: return "MPEG-1 Video";
+ case AP4_OTI_MPEG1_AUDIO: return "MPEG-1 Audio";
+ case AP4_OTI_JPEG: return "JPEG";
+ default: return "UNKNOWN";
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MpegAudioSampleDescription::GetMpeg4AudioObjectTypeString
++---------------------------------------------------------------------*/
+const char*
+AP4_MpegAudioSampleDescription::GetMpeg4AudioObjectTypeString(Mpeg4AudioObjectType type)
+{
+ switch (type) {
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_MAIN: return "AAC Main Profile";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LC: return "AAC Low Complexity";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_SSR: return "AAC Scalable Sample Rate";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LTP: return "AAC Long Term Predictor";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_SBR: return "Spectral Band Replication";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_SCALABLE: return "AAC Scalable";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_TWINVQ: return "Twin VQ";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_CELP: return "CELP";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_HVXC: return "HVXC";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_TTSI: return "TTSI";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_MAIN_SYNTHETIC: return "Main Synthetic";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_WAVETABLE_SYNTHESIS: return "Wavetable Synthesis";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_GENERAL_MIDI: return "General MIDI";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ALGORITHMIC_SYNTHESIS: return "Algorithmic Synthesis";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LC: return "Error Resilient AAC Low Complexity";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LTP: return "Error Resilient AAC Long Term Prediction";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_SCALABLE: return "Error Resilient AAC Scalable";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_TWINVQ: return "Error Resilient Twin VQ";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_BSAC: return "Error Resilient Bit Sliced Arithmetic Coding";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LD: return "Error Resilient AAC Low Delay";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_CELP: return "Error Resilient CELP";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_HVXC: return "Error Resilient HVXC";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_HILN: return "Error Resilient HILN";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_PARAMETRIC: return "Error Resilient Parametric";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_SSC: return "SSC";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_MPEG_SURROUND: return "MPEG Surround";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_LAYER_1: return "MPEG Layer 1";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_LAYER_2: return "MPEG Layer 2";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_LAYER_3: return "MPEG Layer 3";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_DST: return "Direct Stream Transfer";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ALS: return "ALS Lossless Coding";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_SLS: return "SLS Scalable Lossless Coding";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_SLS_NON_CORE: return "SLS Scalable Lossless Coding (Non Core)";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_ELD: return "Error Resilient AAC ELD";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_SIMPLE: return "SMR Simple";
+ case AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_MAIN: return "SMR Main";
+ default: return "UNKNOWN";
+ }
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleDescription.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleDescription.h new file mode 100644 index 000000000..9e60cad7d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleDescription.h @@ -0,0 +1,517 @@ +/***************************************************************** +| +| AP4 - Sample Descriptions +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_SAMPLE_DESCRIPTION_H_ +#define _AP4_SAMPLE_DESCRIPTION_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4EsDescriptor.h" +#include "Ap4EsdsAtom.h" +#include "Ap4Array.h" +#include "Ap4AvccAtom.h" +#include "Ap4DynamicCast.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_SampleEntry; +class AP4_DataBuffer; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define AP4_SAMPLE_FORMAT_MP4A AP4_ATOM_TYPE('m','p','4','a') +#define AP4_SAMPLE_FORMAT_MP4V AP4_ATOM_TYPE('m','p','4','v') +#define AP4_SAMPLE_FORMAT_MP4S AP4_ATOM_TYPE('m','p','4','s') +#define AP4_SAMPLE_FORMAT_AVC1 AP4_ATOM_TYPE('a','v','c','1') +#define AP4_SAMPLE_FORMAT_ALAC AP4_ATOM_TYPE('a','l','a','c') +#define AP4_SAMPLE_FORMAT_OWMA AP4_ATOM_TYPE('o','w','m','a') +#define AP4_SAMPLE_FORMAT_OVC1 AP4_ATOM_TYPE('o','v','c','1') +#define AP4_SAMPLE_FORMAT_AVCP AP4_ATOM_TYPE('a','v','c','p') +#define AP4_SAMPLE_FORMAT_DRAC AP4_ATOM_TYPE('d','r','a','c') +#define AP4_SAMPLE_FORMAT_DRA1 AP4_ATOM_TYPE('d','r','a','1') +#define AP4_SAMPLE_FORMAT_AC_3 AP4_ATOM_TYPE('a','c','-','3') +#define AP4_SAMPLE_FORMAT_EC_3 AP4_ATOM_TYPE('e','c','-','3') +#define AP4_SAMPLE_FORMAT_G726 AP4_ATOM_TYPE('g','7','2','6') +#define AP4_SAMPLE_FORMAT_MJP2 AP4_ATOM_TYPE('m','j','p','2') +#define AP4_SAMPLE_FORMAT_OKSD AP4_ATOM_TYPE('o','k','s','d') +#define AP4_SAMPLE_FORMAT_RAW_ AP4_ATOM_TYPE('r','a','w',' ') +#define AP4_SAMPLE_FORMAT_RTP_ AP4_ATOM_TYPE('r','t','p',' ') +#define AP4_SAMPLE_FORMAT_S263 AP4_ATOM_TYPE('s','2','6','3') +#define AP4_SAMPLE_FORMAT_SAMR AP4_ATOM_TYPE('s','a','m','r') +#define AP4_SAMPLE_FORMAT_SAWB AP4_ATOM_TYPE('s','a','w','b') +#define AP4_SAMPLE_FORMAT_SAWP AP4_ATOM_TYPE('s','a','w','p') +#define AP4_SAMPLE_FORMAT_SEVC AP4_ATOM_TYPE('s','e','v','c') +#define AP4_SAMPLE_FORMAT_SQCP AP4_ATOM_TYPE('s','q','c','p') +#define AP4_SAMPLE_FORMAT_SRTP AP4_ATOM_TYPE('s','r','t','p') +#define AP4_SAMPLE_FORMAT_SSMV AP4_ATOM_TYPE('s','s','m','v') +#define AP4_SAMPLE_FORMAT_TEXT AP4_ATOM_TYPE('t','e','t','x') +#define AP4_SAMPLE_FORMAT_TWOS AP4_ATOM_TYPE('t','w','o','s') +#define AP4_SAMPLE_FORMAT_TX3G AP4_ATOM_TYPE('t','x','3','g') +#define AP4_SAMPLE_FORMAT_VC_1 AP4_ATOM_TYPE('v','c','-','1') +#define AP4_SAMPLE_FORMAT_XML_ AP4_ATOM_TYPE('x','m','l',' ') + +const char* +AP4_GetFormatName(AP4_UI32 format); + +/*---------------------------------------------------------------------- +| AP4_SampleDescription ++---------------------------------------------------------------------*/ +class AP4_SampleDescription +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST(AP4_SampleDescription) + + // type constants of the sample description + enum Type { + TYPE_UNKNOWN = 0x00, + TYPE_MPEG = 0x01, + TYPE_PROTECTED = 0x02, + TYPE_AVC = 0x03 + }; + + // constructors & destructor + AP4_SampleDescription(Type type, + AP4_UI32 format, + AP4_AtomParent* details); + virtual ~AP4_SampleDescription() {} + virtual AP4_SampleDescription* Clone(AP4_Result* result = NULL); + + // accessors + Type GetType() const { return m_Type; } + AP4_UI32 GetFormat() const { return m_Format; } + AP4_AtomParent& GetDetails() { return m_Details; } + + // factories + virtual AP4_Atom* ToAtom() const; + + protected: + Type m_Type; + AP4_UI32 m_Format; + AP4_AtomParent m_Details; +}; + +/*---------------------------------------------------------------------- +| AP4_UnknownSampleDescription ++---------------------------------------------------------------------*/ +class AP4_UnknownSampleDescription : public AP4_SampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_UnknownSampleDescription, AP4_SampleDescription) + + // this constructor takes makes a copy of the atom passed as an argument + AP4_UnknownSampleDescription(AP4_Atom* atom); + ~AP4_UnknownSampleDescription(); + + virtual AP4_SampleDescription* Clone(AP4_Result* result); + virtual AP4_Atom* ToAtom() const; + + // accessor + const AP4_Atom* GetAtom() { return m_Atom; } + +private: + AP4_Atom* m_Atom; +}; + +/*---------------------------------------------------------------------- +| AP4_AudioSampleDescription // MIXIN class ++---------------------------------------------------------------------*/ +class AP4_AudioSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST(AP4_AudioSampleDescription) + + // constructor + AP4_AudioSampleDescription(unsigned int sample_rate, + unsigned int sample_size, + unsigned int channel_count) : + m_SampleRate(sample_rate), + m_SampleSize(sample_size), + m_ChannelCount(channel_count) {} + + // accessors + AP4_UI32 GetSampleRate() { return m_SampleRate; } + AP4_UI16 GetSampleSize() { return m_SampleSize; } + AP4_UI16 GetChannelCount() { return m_ChannelCount; } + +protected: + // members + AP4_UI32 m_SampleRate; + AP4_UI16 m_SampleSize; + AP4_UI16 m_ChannelCount; +}; + +/*---------------------------------------------------------------------- +| AP4_VideoSampleDescription // MIXIN class ++---------------------------------------------------------------------*/ +class AP4_VideoSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST(AP4_VideoSampleDescription) + + // constructor + AP4_VideoSampleDescription(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name) : + m_Width(width), + m_Height(height), + m_Depth(depth), + m_CompressorName(compressor_name) {} + + // accessors + AP4_UI16 GetWidth() { return m_Width; } + AP4_UI16 GetHeight() { return m_Height; } + AP4_UI16 GetDepth() { return m_Depth; } + const char* GetCompressorName() { return m_CompressorName.GetChars(); } + +protected: + // members + AP4_UI16 m_Width; + AP4_UI16 m_Height; + AP4_UI16 m_Depth; + AP4_String m_CompressorName; +}; + +/*---------------------------------------------------------------------- +| AP4_GenericAudioSampleDescription ++---------------------------------------------------------------------*/ +class AP4_GenericAudioSampleDescription : public AP4_SampleDescription, + public AP4_AudioSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_GenericAudioSampleDescription, AP4_SampleDescription, AP4_AudioSampleDescription) + + // constructors + AP4_GenericAudioSampleDescription(AP4_UI32 format, + unsigned int sample_rate, + unsigned int sample_size, + unsigned int channel_count, + AP4_AtomParent* details) : + AP4_SampleDescription(TYPE_UNKNOWN, format, details), + AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) {} +}; + +/*---------------------------------------------------------------------- +| AP4_GenericVideoSampleDescription ++---------------------------------------------------------------------*/ +class AP4_GenericVideoSampleDescription : public AP4_SampleDescription, + public AP4_VideoSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_GenericVideoSampleDescription, AP4_SampleDescription, AP4_VideoSampleDescription) + + // constructor + AP4_GenericVideoSampleDescription(AP4_UI32 format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_AtomParent* details) : + AP4_SampleDescription(TYPE_UNKNOWN, format, details), + AP4_VideoSampleDescription(width, height, depth, compressor_name) {} +}; + +/*---------------------------------------------------------------------- +| AP4_AvcSampleDescription ++---------------------------------------------------------------------*/ +class AP4_AvcSampleDescription : public AP4_SampleDescription, + public AP4_VideoSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_AvcSampleDescription, AP4_SampleDescription, AP4_VideoSampleDescription) + + // constructors + AP4_AvcSampleDescription(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + const AP4_AvccAtom* avcc); + + AP4_AvcSampleDescription(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_AtomParent* details); + + AP4_AvcSampleDescription(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_UI08 profile, + AP4_UI08 level, + AP4_UI08 profile_compatibility, + AP4_UI08 nalu_length_size, + const AP4_Array<AP4_DataBuffer>& sequence_parameters, + const AP4_Array<AP4_DataBuffer>& picture_parameters); + + // accessors + AP4_UI08 GetConfigurationVersion() const { return m_AvccAtom->GetConfigurationVersion(); } + AP4_UI08 GetProfile() const { return m_AvccAtom->GetProfile(); } + AP4_UI08 GetLevel() const { return m_AvccAtom->GetLevel(); } + AP4_UI08 GetProfileCompatibility() const { return m_AvccAtom->GetProfileCompatibility(); } + AP4_UI08 GetNaluLengthSize() const { return m_AvccAtom->GetNaluLengthSize(); } + AP4_Array<AP4_DataBuffer>& GetSequenceParameters() {return m_AvccAtom->GetSequenceParameters(); } + AP4_Array<AP4_DataBuffer>& GetPictureParameters() { return m_AvccAtom->GetPictureParameters(); } + const AP4_DataBuffer& GetRawBytes() const { return m_AvccAtom->GetRawBytes(); } + + // inherited from AP4_SampleDescription + virtual AP4_Atom* ToAtom() const; + + // static methods + static const char* GetProfileName(AP4_UI08 profile) { + return AP4_AvccAtom::GetProfileName(profile); + } + +private: + AP4_AvccAtom* m_AvccAtom; +}; + +/*---------------------------------------------------------------------- +| AP4_MpegSampleDescription ++---------------------------------------------------------------------*/ +class AP4_MpegSampleDescription : public AP4_SampleDescription +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_MpegSampleDescription, AP4_SampleDescription) + + // types + typedef AP4_UI08 StreamType; + typedef AP4_UI08 OTI; + + // class methods + static const char* GetStreamTypeString(StreamType type); + static const char* GetObjectTypeString(OTI oti); + + // constructors & destructor + AP4_MpegSampleDescription(AP4_UI32 format, + AP4_EsdsAtom* esds); + AP4_MpegSampleDescription(AP4_UI32 format, + StreamType stream_type, + OTI oti, + const AP4_DataBuffer* decoder_info, + AP4_UI32 buffer_size, + AP4_UI32 max_bitrate, + AP4_UI32 avg_bitrate); + + // accessors + AP4_Byte GetStreamType() const { return m_StreamType; } + AP4_Byte GetObjectTypeId() const { return m_ObjectTypeId; } + AP4_UI32 GetBufferSize() const { return m_BufferSize; } + AP4_UI32 GetMaxBitrate() const { return m_MaxBitrate; } + AP4_UI32 GetAvgBitrate() const { return m_AvgBitrate; } + const AP4_DataBuffer& GetDecoderInfo() const { return m_DecoderInfo; } + + // methods + AP4_EsDescriptor* CreateEsDescriptor() const; + + protected: + // members + AP4_UI32 m_Format; + StreamType m_StreamType; + OTI m_ObjectTypeId; + AP4_UI32 m_BufferSize; + AP4_UI32 m_MaxBitrate; + AP4_UI32 m_AvgBitrate; + AP4_DataBuffer m_DecoderInfo; +}; + +/*---------------------------------------------------------------------- +| AP4_MpegSystemSampleDescription ++---------------------------------------------------------------------*/ +class AP4_MpegSystemSampleDescription : public AP4_MpegSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_MpegSystemSampleDescription, AP4_MpegSampleDescription) + + // constructor + AP4_MpegSystemSampleDescription(AP4_EsdsAtom* esds); + AP4_MpegSystemSampleDescription(StreamType stream_type, + OTI oti, + const AP4_DataBuffer* decoder_info, + AP4_UI32 buffer_size, + AP4_UI32 max_bitrate, + AP4_UI32 avg_bitrate); + + // methods + AP4_Atom* ToAtom() const; +}; + +/*---------------------------------------------------------------------- +| AP4_MpegAudioSampleDescription ++---------------------------------------------------------------------*/ +class AP4_MpegAudioSampleDescription : public AP4_MpegSampleDescription, + public AP4_AudioSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_MpegAudioSampleDescription, AP4_MpegSampleDescription, AP4_AudioSampleDescription) + + // types + typedef AP4_UI08 Mpeg4AudioObjectType; + + // class methods + static const char* GetMpeg4AudioObjectTypeString(Mpeg4AudioObjectType type); + + // constructor + AP4_MpegAudioSampleDescription(unsigned int sample_rate, + unsigned int sample_size, + unsigned int channel_count, + AP4_EsdsAtom* esds); + + AP4_MpegAudioSampleDescription(OTI oti, + unsigned int sample_rate, + unsigned int sample_size, + unsigned int channel_count, + const AP4_DataBuffer* decoder_info, + AP4_UI32 buffer_size, + AP4_UI32 max_bitrate, + AP4_UI32 avg_bitrate); + + // methods + AP4_Atom* ToAtom() const; + + /** + * For sample descriptions of MPEG-4 audio tracks (i.e GetObjectTypeId() + * returns AP4_OTI_MPEG4_AUDIO), this method returns the MPEG4 Audio Object + * Type. For other sample descriptions, this method returns 0. + */ + Mpeg4AudioObjectType GetMpeg4AudioObjectType() const; +}; + +/*---------------------------------------------------------------------- +| AP4_MpegVideoSampleDescription ++---------------------------------------------------------------------*/ +class AP4_MpegVideoSampleDescription : public AP4_MpegSampleDescription, + public AP4_VideoSampleDescription +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D2(AP4_MpegVideoSampleDescription, AP4_MpegSampleDescription, AP4_VideoSampleDescription) + + // constructor + AP4_MpegVideoSampleDescription(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_EsdsAtom* esds); + + AP4_MpegVideoSampleDescription(OTI oti, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + const AP4_DataBuffer* decoder_info, + AP4_UI32 buffer_size, + AP4_UI32 max_bitrate, + AP4_UI32 avg_bitrate); + + // methods + AP4_Atom* ToAtom() const; +}; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_FORBIDDEN = 0x00; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_OD = 0x01; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_CR = 0x02; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_BIFS = 0x03; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_VISUAL = 0x04; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_AUDIO = 0x05; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_MPEG7 = 0x06; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_IPMP = 0x07; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_OCI = 0x08; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_MPEGJ = 0x09; +const AP4_MpegSampleDescription::StreamType AP4_STREAM_TYPE_TEXT = 0x0D; + +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG4_SYSTEM = 0x01; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG4_SYSTEM_COR = 0x02; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG4_TEXT = 0x08; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG4_VISUAL = 0x20; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG4_AUDIO = 0x40; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_VISUAL_SIMPLE = 0x60; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_VISUAL_MAIN = 0x61; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_VISUAL_SNR = 0x62; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_VISUAL_SPATIAL = 0x63; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_VISUAL_HIGH = 0x64; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_VISUAL_422 = 0x65; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_AAC_AUDIO_MAIN = 0x66; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_AAC_AUDIO_LC = 0x67; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_AAC_AUDIO_SSRP = 0x68; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG2_PART3_AUDIO = 0x69; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG1_VISUAL = 0x6A; +const AP4_MpegSampleDescription::OTI AP4_OTI_MPEG1_AUDIO = 0x6B; +const AP4_MpegSampleDescription::OTI AP4_OTI_JPEG = 0x6C; + +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_MAIN = 1; /**< AAC Main Profile */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LC = 2; /**< AAC Low Complexity */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_SSR = 3; /**< AAC Scalable Sample Rate */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_LTP = 4; /**< AAC Long Term Predictor */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SBR = 5; /**< Spectral Band Replication */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_AAC_SCALABLE = 6; /**< AAC Scalable */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_TWINVQ = 7; /**< Twin VQ */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_CELP = 8; /**< CELP */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_HVXC = 9; /**< HVXC */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_TTSI = 12; /**< TTSI */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_MAIN_SYNTHETIC = 13; /**< Main Synthetic */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_WAVETABLE_SYNTHESIS = 14; /**< WavetableSynthesis */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_GENERAL_MIDI = 15; /**< General MIDI */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ALGORITHMIC_SYNTHESIS = 16; /**< Algorithmic Synthesis */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LC = 17; /**< Error Resilient AAC Low Complexity */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LTP = 19; /**< Error Resilient AAC Long Term Prediction */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_SCALABLE = 20; /**< Error Resilient AAC Scalable */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_TWINVQ = 21; /**< Error Resilient Twin VQ */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_BSAC = 22; /**< Error Resilient Bit Sliced Arithmetic Coding */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_LD = 23; /**< Error Resilient AAC Low Delay */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_CELP = 24; /**< Error Resilient CELP */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_HVXC = 25; /**< Error Resilient HVXC */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_HILN = 26; /**< Error Resilient HILN */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_PARAMETRIC = 27; /**< Error Resilient Parametric */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SSC = 28; /**< SSC */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_PS = 29; /**< Parametric Stereo */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_MPEG_SURROUND = 30; /**< MPEG Surround */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_LAYER_1 = 32; /**< MPEG Layer 1 */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_LAYER_2 = 33; /**< MPEG Layer 2 */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_LAYER_3 = 34; /**< MPEG Layer 3 */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_DST = 35; /**< DST Direct Stream Transfer */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ALS = 36; /**< ALS Lossless Coding */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SLS = 37; /**< SLS Scalable Lossless Coding */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SLS_NON_CORE = 38; /**< SLS Sclable Lossless Coding Non-Core */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_ER_AAC_ELD = 39; /**< Error Resilient AAC ELD */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_SIMPLE = 40; /**< SMR Simple */ +const AP4_UI08 AP4_MPEG4_AUDIO_OBJECT_TYPE_SMR_MAIN = 41; /**< SMR Main */ + +// ==> Start patch MPC +const AP4_MpegSampleDescription::OTI AP4_NERO_VOBSUB = 0xE0;
+// <== End patch MPC
+ +#endif // _AP4_SAMPLE_DESCRIPTION_H_ + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleEntry.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleEntry.cpp new file mode 100644 index 000000000..086401b01 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleEntry.cpp @@ -0,0 +1,1382 @@ +/***************************************************************** +| +| AP4 - sample entries +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SampleEntry.h" +#include "Ap4Utils.h" +#include "Ap4AtomFactory.h" +#include "Ap4TimsAtom.h" +#include "Ap4SampleDescription.h" +#include "Ap4AvccAtom.h" +// ==> Start patch MPC +#include "Ap4FtabAtom.h" +// <== End patch MPC + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_SampleEntry) + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::AP4_SampleEntry ++---------------------------------------------------------------------*/ +AP4_SampleEntry::AP4_SampleEntry(AP4_Atom::Type format, + AP4_UI16 data_reference_index) : + AP4_ContainerAtom(format), + m_DataReferenceIndex(data_reference_index) +{ + m_Reserved1[0] = 0; + m_Reserved1[1] = 0; + m_Reserved1[2] = 0; + m_Reserved1[3] = 0; + m_Reserved1[4] = 0; + m_Reserved1[5] = 0; + m_Size32 += 8; +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::AP4_SampleEntry ++---------------------------------------------------------------------*/ +AP4_SampleEntry::AP4_SampleEntry(AP4_Atom::Type format, + AP4_Size size) : + AP4_ContainerAtom(format, size, false) +{ +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::AP4_SampleEntry ++---------------------------------------------------------------------*/ +AP4_SampleEntry::AP4_SampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_ContainerAtom(format, size, false) +{ + Read(stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::Read ++---------------------------------------------------------------------*/ +void +AP4_SampleEntry::Read(AP4_ByteStream& stream, AP4_AtomFactory& atom_factory) +{ + // read the fields before the children atoms + ReadFields(stream); + + // read children atoms (ex: esds and maybe others) + // NOTE: not all sample entries have children atoms + AP4_Size payload_size = (AP4_Size)(GetSize()-GetHeaderSize()); + AP4_Size fields_size = GetFieldsSize(); + if (payload_size > fields_size) { + ReadChildren(atom_factory, stream, payload_size-fields_size); + } +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::GetFieldsSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_SampleEntry::GetFieldsSize() +{ + return 8; +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SampleEntry::ReadFields(AP4_ByteStream& stream) +{ + stream.Read(m_Reserved1, sizeof(m_Reserved1)); + stream.ReadUI16(m_DataReferenceIndex); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SampleEntry::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // reserved1 + result = stream.Write(m_Reserved1, sizeof(m_Reserved1)); + if (AP4_FAILED(result)) return result; + + // data reference index + result = stream.WriteUI16(m_DataReferenceIndex); + if (AP4_FAILED(result)) return result; + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::Write ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SampleEntry::Write(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the header + result = WriteHeader(stream); + if (AP4_FAILED(result)) return result; + + // write the fields + result = WriteFields(stream); + if (AP4_FAILED(result)) return result; + + // write the children atoms + return m_Children.Apply(AP4_AtomListWriter(stream)); +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SampleEntry::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("data_reference_index", m_DataReferenceIndex); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::Inspect ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SampleEntry::Inspect(AP4_AtomInspector& inspector) +{ + // inspect the header + InspectHeader(inspector); + + // inspect the fields + InspectFields(inspector); + + // inspect children + m_Children.Apply(AP4_AtomListInspector(inspector)); + + // finish + inspector.EndElement(); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::OnChildChanged ++---------------------------------------------------------------------*/ +void +AP4_SampleEntry::OnChildChanged(AP4_Atom*) +{ + // recompute our size + AP4_UI64 size = GetHeaderSize()+GetFieldsSize(); + m_Children.Apply(AP4_AtomSizeAdder(size)); + m_Size32 = (AP4_UI32)size; + + // update our parent + if (m_Parent) m_Parent->OnChildChanged(this); +} + +/*---------------------------------------------------------------------- +| AP4_SampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_SampleEntry::ToSampleDescription() +{ + return new AP4_SampleDescription(AP4_SampleDescription::TYPE_UNKNOWN, m_Type, this); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownSampleEntry::AP4_UnknownSampleEntry ++---------------------------------------------------------------------*/ +AP4_UnknownSampleEntry::AP4_UnknownSampleEntry(AP4_Atom::Type type, + AP4_Size size, + AP4_ByteStream& stream) : + AP4_SampleEntry(type, size) +{ + if (size > AP4_ATOM_HEADER_SIZE+AP4_SampleEntry::GetFieldsSize()) { + m_Payload.SetDataSize(size-(AP4_ATOM_HEADER_SIZE+AP4_SampleEntry::GetFieldsSize())); + ReadFields(stream); + } +} + +/*---------------------------------------------------------------------- +| AP4_UnknownSampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_UnknownSampleEntry::ToSampleDescription() +{ + return new AP4_UnknownSampleDescription(this); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownSampleEntry::GetFieldsSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_UnknownSampleEntry::GetFieldsSize() +{ + return AP4_SampleEntry::GetFieldsSize()+m_Payload.GetDataSize(); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownSampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_UnknownSampleEntry::ReadFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::ReadFields(stream); + if (AP4_FAILED(result)) return result; + + // read the payload + return stream.Read(m_Payload.UseData(), m_Payload.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| AP4_UnknownSampleEntry::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_UnknownSampleEntry::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the fields of the base class + result = AP4_SampleEntry::WriteFields(stream); + if (AP4_FAILED(result)) return result; + + // write the payload + return stream.Write(m_Payload.GetData(), m_Payload.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| AP4_MpegSystemSampleEntry::AP4_MpegSystemSampleEntry ++---------------------------------------------------------------------*/ +AP4_MpegSystemSampleEntry::AP4_MpegSystemSampleEntry( + AP4_UI32 type, + AP4_EsDescriptor* descriptor) : + AP4_SampleEntry(type) +{ + if (descriptor) AddChild(new AP4_EsdsAtom(descriptor)); +} + +/*---------------------------------------------------------------------- +| AP4_MpegSystemSampleEntry::AP4_MpegSystemSampleEntry ++---------------------------------------------------------------------*/ +AP4_MpegSystemSampleEntry::AP4_MpegSystemSampleEntry( + AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_SampleEntry(type, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_MpegSystemSampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_MpegSystemSampleEntry::ToSampleDescription() +{ + return new AP4_MpegSystemSampleDescription( + AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS))); +} + +/*---------------------------------------------------------------------- +| AP4_Mp4sSampleEntry::AP4_Mp4sSampleEntry ++---------------------------------------------------------------------*/ +AP4_Mp4sSampleEntry::AP4_Mp4sSampleEntry(AP4_EsDescriptor* descriptor) : + AP4_MpegSystemSampleEntry(AP4_ATOM_TYPE_MP4S, descriptor) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Mp4sSampleEntry::AP4_Mp4sSampleEntry ++---------------------------------------------------------------------*/ +AP4_Mp4sSampleEntry::AP4_Mp4sSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_MpegSystemSampleEntry(AP4_ATOM_TYPE_MP4S, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Mp4sSampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_Mp4sSampleEntry::ToSampleDescription() +{ + // create a sample description + return new AP4_MpegSystemSampleDescription( + AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS))); +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::AP4_AudioSampleEntry ++---------------------------------------------------------------------*/ +AP4_AudioSampleEntry::AP4_AudioSampleEntry(AP4_Atom::Type format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count) : + AP4_SampleEntry(format), + m_QtVersion(0), + m_QtRevision(0), + m_QtVendor(0), + m_ChannelCount(channel_count), + m_SampleSize(sample_size), + m_QtCompressionId(0), + m_QtPacketSize(0), + m_SampleRate(sample_rate), + m_QtV1SamplesPerPacket(0), + m_QtV1BytesPerPacket(0), + m_QtV1BytesPerFrame(0), + m_QtV1BytesPerSample(0), + m_QtV2StructSize(0), + m_QtV2SampleRate64(0.0), + m_QtV2ChannelCount(0), + m_QtV2Reserved(0), + m_QtV2BitsPerChannel(0), + m_QtV2FormatSpecificFlags(0), + m_QtV2BytesPerAudioPacket(0), + m_QtV2LPCMFramesPerAudioPacket(0) +{ + m_Size32 += 20; +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::AP4_AudioSampleEntry ++---------------------------------------------------------------------*/ +AP4_AudioSampleEntry::AP4_AudioSampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_SampleEntry(format, size) +{ + Read(stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::GetFieldsSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_AudioSampleEntry::GetFieldsSize() +{ + AP4_Size size = AP4_SampleEntry::GetFieldsSize()+20; + if (m_QtVersion == 1) { + size += 16; + } else if (m_QtVersion == 2) { + size += 36+m_QtV2Extension.GetDataSize(); + } + + return size; +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::GetSampleRate ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_AudioSampleEntry::GetSampleRate() +{ + if (m_QtVersion == 2) { + return (AP4_UI32)(m_QtV2SampleRate64); + } else { + return m_SampleRate>>16; + } +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::GetChannelCount ++---------------------------------------------------------------------*/ +AP4_UI16 +AP4_AudioSampleEntry::GetChannelCount() +{ + if (m_QtVersion == 2) { + return m_QtV2ChannelCount; + } else { + return m_ChannelCount; + } +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AudioSampleEntry::ReadFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::ReadFields(stream); + if (result < 0) return result; + + // read the fields of this class + stream.ReadUI16(m_QtVersion); + stream.ReadUI16(m_QtRevision); + stream.ReadUI32(m_QtVendor); + stream.ReadUI16(m_ChannelCount); + stream.ReadUI16(m_SampleSize); + stream.ReadUI16(m_QtCompressionId); + stream.ReadUI16(m_QtPacketSize); + stream.ReadUI32(m_SampleRate); + + // if this is a QT V1 entry, read the extension + if (m_QtVersion == 1) { + stream.ReadUI32(m_QtV1SamplesPerPacket); + stream.ReadUI32(m_QtV1BytesPerPacket); + stream.ReadUI32(m_QtV1BytesPerFrame); + stream.ReadUI32(m_QtV1BytesPerSample); + } else if (m_QtVersion == 2) { + stream.ReadUI32(m_QtV2StructSize); + stream.ReadDouble(m_QtV2SampleRate64); + stream.ReadUI32(m_QtV2ChannelCount); + stream.ReadUI32(m_QtV2Reserved); + stream.ReadUI32(m_QtV2BitsPerChannel); + stream.ReadUI32(m_QtV2FormatSpecificFlags); + stream.ReadUI32(m_QtV2BytesPerAudioPacket); + stream.ReadUI32(m_QtV2LPCMFramesPerAudioPacket); + if (m_QtV2StructSize > 72) { + unsigned int ext_size = m_QtV2StructSize-72; + m_QtV2Extension.SetDataSize(ext_size); + stream.Read(m_QtV2Extension.UseData(), ext_size); + } + m_QtV1SamplesPerPacket = + m_QtV1BytesPerPacket = + m_QtV1BytesPerFrame = + m_QtV1BytesPerSample = 0; + } else { + m_QtV1SamplesPerPacket = 0; + m_QtV1BytesPerPacket = 0; + m_QtV1BytesPerFrame = 0; + m_QtV1BytesPerSample = 0; + m_QtV2StructSize = 0; + m_QtV2SampleRate64 = 0.0; + m_QtV2ChannelCount = 0; + m_QtV2Reserved = 0; + m_QtV2BitsPerChannel = 0; + m_QtV2FormatSpecificFlags = 0; + m_QtV2BytesPerAudioPacket = 0; + m_QtV2LPCMFramesPerAudioPacket = 0; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AudioSampleEntry::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the fields of the base class + result = AP4_SampleEntry::WriteFields(stream); + + // QT version + result = stream.WriteUI16(m_QtVersion); + if (AP4_FAILED(result)) return result; + + // QT revision + result = stream.WriteUI16(m_QtRevision); + if (AP4_FAILED(result)) return result; + + // QT vendor + result = stream.WriteUI32(m_QtVendor); + if (AP4_FAILED(result)) return result; + + // channel count + result = stream.WriteUI16(m_ChannelCount); + if (AP4_FAILED(result)) return result; + + // sample size + result = stream.WriteUI16(m_SampleSize); + if (AP4_FAILED(result)) return result; + + // QT compression ID + result = stream.WriteUI16(m_QtCompressionId); + if (AP4_FAILED(result)) return result; + + // QT packet size + result = stream.WriteUI16(m_QtPacketSize); + if (AP4_FAILED(result)) return result; + + // sample rate + result = stream.WriteUI32(m_SampleRate); + if (AP4_FAILED(result)) return result; + + if (m_QtVersion == 1) { + result = stream.WriteUI32(m_QtV1SamplesPerPacket); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_QtV1BytesPerPacket); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_QtV1BytesPerFrame); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_QtV1BytesPerSample); + if (AP4_FAILED(result)) return result; + } else if (m_QtVersion == 2) { + stream.WriteUI32(m_QtV2StructSize); + stream.WriteDouble(m_QtV2SampleRate64); + stream.WriteUI32(m_QtV2ChannelCount); + stream.WriteUI32(m_QtV2Reserved); + stream.WriteUI32(m_QtV2BitsPerChannel); + stream.WriteUI32(m_QtV2FormatSpecificFlags); + stream.WriteUI32(m_QtV2BytesPerAudioPacket); + stream.WriteUI32(m_QtV2LPCMFramesPerAudioPacket); + if (m_QtV2Extension.GetDataSize()) { + stream.Write(m_QtV2Extension.GetData(), + m_QtV2Extension.GetDataSize()); + } + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AudioSampleEntry::InspectFields(AP4_AtomInspector& inspector) +{ + // dump the fields from the base class + AP4_SampleEntry::InspectFields(inspector); + + // fields + inspector.AddField("channel_count", GetChannelCount()); + inspector.AddField("sample_size", GetSampleSize()); + inspector.AddField("sample_rate", GetSampleRate()); + if (m_QtVersion) { + inspector.AddField("qt_version", m_QtVersion); + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_AudioSampleEntry::ToSampleDescription() +{ + // create a sample description + return new AP4_GenericAudioSampleDescription( + m_Type, + GetSampleRate(), + GetSampleSize(), + GetChannelCount(), + this); +} + +/*---------------------------------------------------------------------- +| AP4_MpegAudioSampleEntry::AP4_MpegAudioSampleEntry ++---------------------------------------------------------------------*/ +AP4_MpegAudioSampleEntry::AP4_MpegAudioSampleEntry( + AP4_UI32 type, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_EsDescriptor* descriptor) : + AP4_AudioSampleEntry(type, sample_rate, sample_size, channel_count) +{ + if (descriptor) AddChild(new AP4_EsdsAtom(descriptor)); +} + +/*---------------------------------------------------------------------- +| AP4_MpegAudioSampleEntry::AP4_MpegAudioSampleEntry ++---------------------------------------------------------------------*/ +AP4_MpegAudioSampleEntry::AP4_MpegAudioSampleEntry( + AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_AudioSampleEntry(type, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_MpegAudioSampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_MpegAudioSampleEntry::ToSampleDescription() +{ + // find the esds atom + AP4_EsdsAtom* esds = AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS)); + if (esds == NULL) { + // check if this is a quicktime style sample description + if (m_QtVersion > 0) { + esds = AP4_DYNAMIC_CAST(AP4_EsdsAtom, FindChild("wave/esds")); + } + } + + // create a sample description + return new AP4_MpegAudioSampleDescription(GetSampleRate(), + GetSampleSize(), + GetChannelCount(), + esds); +} + +/*---------------------------------------------------------------------- +| AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry ++---------------------------------------------------------------------*/ +AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_EsDescriptor* descriptor) : + AP4_MpegAudioSampleEntry(AP4_ATOM_TYPE_MP4A, + sample_rate, + sample_size, + channel_count, + descriptor) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry ++---------------------------------------------------------------------*/ +AP4_Mp4aSampleEntry::AP4_Mp4aSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_MpegAudioSampleEntry(AP4_ATOM_TYPE_MP4A, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry::AP4_VisualSampleEntry ++---------------------------------------------------------------------*/ +AP4_VisualSampleEntry::AP4_VisualSampleEntry( + AP4_Atom::Type format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name) : + AP4_SampleEntry(format), + m_Predefined1(0), + m_Reserved2(0), + m_Width(width), + m_Height(height), + m_HorizResolution(0x00480000), + m_VertResolution(0x00480000), + m_Reserved3(0), + m_FrameCount(1), + m_CompressorName(compressor_name), + m_Depth(depth), + m_Predefined3(0xFFFF) +{ + memset(m_Predefined2, 0, sizeof(m_Predefined2)); + m_Size32 += 70; +} + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry::AP4_VisualSampleEntry ++---------------------------------------------------------------------*/ +AP4_VisualSampleEntry::AP4_VisualSampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_SampleEntry(format, size) +{ + Read(stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry::GetFieldsSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_VisualSampleEntry::GetFieldsSize() +{ + return AP4_SampleEntry::GetFieldsSize()+70; +} + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_VisualSampleEntry::ReadFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::ReadFields(stream); + if (result < 0) return result; + + // read fields from this class + stream.ReadUI16(m_Predefined1); + stream.ReadUI16(m_Reserved2); + stream.Read(m_Predefined2, sizeof(m_Predefined2)); + stream.ReadUI16(m_Width); + stream.ReadUI16(m_Height); + stream.ReadUI32(m_HorizResolution); + stream.ReadUI32(m_VertResolution); + stream.ReadUI32(m_Reserved3); + stream.ReadUI16(m_FrameCount); + + char compressor_name[33]; + stream.Read(compressor_name, 32); + int name_length = compressor_name[0]; + if (name_length < 32) { + compressor_name[name_length+1] = 0; // force null termination + m_CompressorName = &compressor_name[1]; + } + + stream.ReadUI16(m_Depth); + stream.ReadUI16(m_Predefined3); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_VisualSampleEntry::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the fields of the base class + result = AP4_SampleEntry::WriteFields(stream); + if (AP4_FAILED(result)) return result; + + // predefined1 + result = stream.WriteUI16(m_Predefined1); + if (AP4_FAILED(result)) return result; + + // reserved2 + result = stream.WriteUI16(m_Reserved2); + if (AP4_FAILED(result)) return result; + + // predefined2 + result = stream.Write(m_Predefined2, sizeof(m_Predefined2)); + if (AP4_FAILED(result)) return result; + + // width + result = stream.WriteUI16(m_Width); + if (AP4_FAILED(result)) return result; + + // height + result = stream.WriteUI16(m_Height); + if (AP4_FAILED(result)) return result; + + // horizontal resolution + result = stream.WriteUI32(m_HorizResolution); + if (AP4_FAILED(result)) return result; + + // vertical resolution + result = stream.WriteUI32(m_VertResolution); + if (AP4_FAILED(result)) return result; + + // reserved3 + result = stream.WriteUI32(m_Reserved3); + if (AP4_FAILED(result)) return result; + + // frame count + result = stream.WriteUI16(m_FrameCount); + if (AP4_FAILED(result)) return result; + + // compressor name + unsigned char compressor_name[32]; + unsigned int name_length = m_CompressorName.GetLength(); + if (name_length > 31) name_length = 31; + compressor_name[0] = name_length; + for (unsigned int i=0; i<name_length; i++) { + compressor_name[i+1] = m_CompressorName[i]; + } + for (unsigned int i=name_length+1; i<32; i++) { + compressor_name[i] = 0; + } + result = stream.Write(compressor_name, 32); + if (AP4_FAILED(result)) return result; + + // depth + result = stream.WriteUI16(m_Depth); + if (AP4_FAILED(result)) return result; + + // predefined3 + result = stream.WriteUI16(m_Predefined3); + if (AP4_FAILED(result)) return result; + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_VisualSampleEntry::InspectFields(AP4_AtomInspector& inspector) +{ + // dump the fields of the base class + AP4_SampleEntry::InspectFields(inspector); + + // fields + inspector.AddField("width", m_Width); + inspector.AddField("height", m_Height); + inspector.AddField("compressor", m_CompressorName.GetChars()); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_VisualSampleEntry::ToSampleDescription() +{ + // create a sample description + return new AP4_GenericVideoSampleDescription( + m_Type, + m_Width, + m_Height, + m_Depth, + m_CompressorName.GetChars(), + this); +} + +/*---------------------------------------------------------------------- +| AP4_MpegVideoSampleEntry::AP4_MpegVideoSampleEntry ++---------------------------------------------------------------------*/ +AP4_MpegVideoSampleEntry::AP4_MpegVideoSampleEntry( + AP4_UI32 type, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_EsDescriptor* descriptor) : + AP4_VisualSampleEntry(type, + width, + height, + depth, + compressor_name) +{ + if (descriptor) AddChild(new AP4_EsdsAtom(descriptor)); +} + +/*---------------------------------------------------------------------- +| AP4_MpegVideoSampleEntry::AP4_MpegVideoSampleEntry ++---------------------------------------------------------------------*/ +AP4_MpegVideoSampleEntry::AP4_MpegVideoSampleEntry( + AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_VisualSampleEntry(type, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_MpegVideoSampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_MpegVideoSampleEntry::ToSampleDescription() +{ + // create a sample description + return new AP4_MpegVideoSampleDescription( + m_Width, + m_Height, + m_Depth, + m_CompressorName.GetChars(), + AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS))); +} + +/*---------------------------------------------------------------------- +| AP4_Mp4vSampleEntry::AP4_Mp4vSampleEntry ++---------------------------------------------------------------------*/ +AP4_Mp4vSampleEntry::AP4_Mp4vSampleEntry(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_EsDescriptor* descriptor) : + AP4_MpegVideoSampleEntry(AP4_ATOM_TYPE_MP4V, + width, + height, + depth, + compressor_name, + descriptor) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Mp4vSampleEntry::AP4_Mp4aSampleEntry ++---------------------------------------------------------------------*/ +AP4_Mp4vSampleEntry::AP4_Mp4vSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_MpegVideoSampleEntry(AP4_ATOM_TYPE_MP4V, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Avc1SampleEntry::AP4_Avc1SampleEntry ++---------------------------------------------------------------------*/ +AP4_Avc1SampleEntry::AP4_Avc1SampleEntry(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + const AP4_AvccAtom& avcc) : + AP4_VisualSampleEntry(AP4_ATOM_TYPE_AVC1, + width, + height, + depth, + compressor_name) +{ + AddChild(new AP4_AvccAtom(avcc)); +} + +/*---------------------------------------------------------------------- +| AP4_Avc1SampleEntry::AP4_Avc1SampleEntry ++---------------------------------------------------------------------*/ +AP4_Avc1SampleEntry::AP4_Avc1SampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_VisualSampleEntry(AP4_ATOM_TYPE_AVC1, size, stream, atom_factory) +{ +} + +/*---------------------------------------------------------------------- +| AP4_Avc1SampleEntry::ToSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_Avc1SampleEntry::ToSampleDescription() +{ + return new AP4_AvcSampleDescription( + m_Width, + m_Height, + m_Depth, + m_CompressorName.GetChars(), + AP4_DYNAMIC_CAST(AP4_AvccAtom, GetChild(AP4_ATOM_TYPE_AVCC))); +} + +/*---------------------------------------------------------------------- +| AP4_RtpHintSampleEntry::AP4_RtpHintSampleEntry ++---------------------------------------------------------------------*/ +AP4_RtpHintSampleEntry::AP4_RtpHintSampleEntry(AP4_UI16 hint_track_version, + AP4_UI16 highest_compatible_version, + AP4_UI32 max_packet_size, + AP4_UI32 timescale): + AP4_SampleEntry(AP4_ATOM_TYPE_RTP_), + m_HintTrackVersion(hint_track_version), + m_HighestCompatibleVersion(highest_compatible_version), + m_MaxPacketSize(max_packet_size) +{ + // build an atom for timescale + AddChild(new AP4_TimsAtom(timescale)); +} + +/*---------------------------------------------------------------------- +| AP4_RtpHintSampleEntry::AP4_RtpHintSampleEntry ++---------------------------------------------------------------------*/ +AP4_RtpHintSampleEntry::AP4_RtpHintSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory): + AP4_SampleEntry(AP4_ATOM_TYPE_RTP_, size) +{ + Read(stream, atom_factory); +} + +/*---------------------------------------------------------------------- +| AP4_RtpHintSampleEntry::GetFieldsSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_RtpHintSampleEntry::GetFieldsSize() +{ + return AP4_SampleEntry::GetFieldsSize()+8; +} + +/*---------------------------------------------------------------------- +| AP4_RtpHintSampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpHintSampleEntry::ReadFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::ReadFields(stream); + if (result < 0) return result; + + // data + result = stream.ReadUI16(m_HintTrackVersion); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_HighestCompatibleVersion); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI32(m_MaxPacketSize); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_RtpHintSampleEntry::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpHintSampleEntry::WriteFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::WriteFields(stream); + if (AP4_FAILED(result)) return result; + + // data + result = stream.WriteUI16(m_HintTrackVersion); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI16(m_HighestCompatibleVersion); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_MaxPacketSize); + if (AP4_FAILED(result)) return result; + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_RtpHintSampleEntry::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_RtpHintSampleEntry::InspectFields(AP4_AtomInspector& inspector) +{ + // sample entry + AP4_SampleEntry::InspectFields(inspector); + + // fields + inspector.AddField("hint_track_version", m_HintTrackVersion); + inspector.AddField("highest_compatible_version", m_HighestCompatibleVersion); + inspector.AddField("max_packet_size", m_MaxPacketSize); + + return AP4_SUCCESS; +} + +// ==> Start patch MPC +/*---------------------------------------------------------------------- +| AP4_TextSampleEntry::AP4_TextSampleEntry ++---------------------------------------------------------------------*/ +AP4_TextSampleEntry::AP4_TextSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory): + AP4_SampleEntry(AP4_ATOM_TYPE_TEXT, size) +{ + // read fields + ReadFields(stream); +} + +/*---------------------------------------------------------------------- +| AP4_TextSampleEntry::~AP4_TextSampleEntry ++---------------------------------------------------------------------*/ +AP4_TextSampleEntry::~AP4_TextSampleEntry() +{ +} + +/*---------------------------------------------------------------------- +| AP4_TextSampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TextSampleEntry::ReadFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::ReadFields(stream); + if (result < 0) return result; + + // data + result = stream.ReadUI32(m_Description.DisplayFlags); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI32(m_Description.TextJustification); + if (AP4_FAILED(result)) return result; + result = stream.Read(&m_Description.BackgroundColor, 4); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Top); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Left); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Bottom); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Right); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.Style.StartChar); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.Style.EndChar); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.Style.Ascent); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.Style.Font.Id); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI08(m_Description.Style.Font.Face); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI08(m_Description.Style.Font.Size); + if (AP4_FAILED(result)) return result; + result = stream.Read(&m_Description.Style.Font.Color, 4); + if (AP4_FAILED(result)) return result; + + // TODO: stream.ReadString(); -> m_Description.DefaultFontName + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_TextSampleEntry::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TextSampleEntry::WriteFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::WriteFields(stream); + if (AP4_FAILED(result)) return result; + + // TODO: data + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_TextSampleEntry::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TextSampleEntry::InspectFields(AP4_AtomInspector& inspector) +{ + // sample entry + AP4_SampleEntry::InspectFields(inspector); + + // TODO: fields + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry::AP4_Tx3gSampleEntry ++---------------------------------------------------------------------*/ +AP4_Tx3gSampleEntry::AP4_Tx3gSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory): + AP4_SampleEntry(AP4_ATOM_TYPE_TX3G, size) +{ + // read fields + AP4_Size fields_size = GetFieldsSize(); + ReadFields(stream); + + // read children atoms (fdat? blnk?) + ReadChildren(atom_factory, stream, size-AP4_ATOM_HEADER_SIZE-fields_size); +} + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry::~AP4_Tx3gSampleEntry ++---------------------------------------------------------------------*/ +AP4_Tx3gSampleEntry::~AP4_Tx3gSampleEntry() +{ +} + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry::GetFieldsSize ++---------------------------------------------------------------------*/ +AP4_Size +AP4_Tx3gSampleEntry::GetFieldsSize() +{ + return AP4_SampleEntry::GetFieldsSize()+4+1+1+4+2+2+2+2+2+2+2+1+1+4; +} + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Tx3gSampleEntry::ReadFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::ReadFields(stream); + if (result < 0) return result; + + // data + result = stream.ReadUI32(m_Description.DisplayFlags); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI08(m_Description.HorizontalJustification); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI08(m_Description.VerticalJustification); + if (AP4_FAILED(result)) return result; + result = stream.Read(&m_Description.BackgroundColor, 4); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Top); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Left); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Bottom); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.TextBox.Right); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.Style.StartChar); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.Style.EndChar); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI16(m_Description.Style.Font.Id); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI08(m_Description.Style.Font.Face); + if (AP4_FAILED(result)) return result; + result = stream.ReadUI08(m_Description.Style.Font.Size); + if (AP4_FAILED(result)) return result; + result = stream.Read(&m_Description.Style.Font.Color, 4); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Tx3gSampleEntry::WriteFields(AP4_ByteStream& stream) +{ + // sample entry + AP4_Result result = AP4_SampleEntry::WriteFields(stream); + if (AP4_FAILED(result)) return result; + + // TODO: data + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Tx3gSampleEntry::InspectFields(AP4_AtomInspector& inspector) +{ + // sample entry + AP4_SampleEntry::InspectFields(inspector); + + // TODO: fields + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry::GetFontNameById ++---------------------------------------------------------------------*/ + +AP4_Result +AP4_Tx3gSampleEntry::GetFontNameById(AP4_Ordinal Id, AP4_String& Name) +{ + if(AP4_FtabAtom* ftab = dynamic_cast<AP4_FtabAtom*>(GetChild(AP4_ATOM_TYPE_FTAB))) + { + AP4_Array<AP4_FtabAtom::AP4_Tx3gFontRecord> FontRecords = ftab->GetFontRecords(); + + for(int i = 0, j = FontRecords.ItemCount(); i < j; i++) + { + if(Id == FontRecords[i].Id) + { + Name = FontRecords[i].Name; + return AP4_SUCCESS; + } + } + } + + return AP4_FAILURE; +} + + + + +/*---------------------------------------------------------------------- +| AP4_AC3SampleEntry::AP4_AC3SampleEntry ++---------------------------------------------------------------------*/ +AP4_AC3SampleEntry::AP4_AC3SampleEntry(AP4_Atom::Type format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count) : + AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count) +{ +} + +AP4_AC3SampleEntry::AP4_AC3SampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_AudioSampleEntry(format, size, stream, atom_factory) +{ +} + + +/*---------------------------------------------------------------------- +| AP4_AC3SampleEntry::ReadFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AC3SampleEntry::ReadFields(AP4_ByteStream& stream) +{ + + AP4_AudioSampleEntry::ReadFields(stream); + + // SampleSize field from AudioSampleEntry shall be ignored + m_SampleSize = 0; + + // AC3SpecificBox + + // BoxHeader.Size, BoxHeader.Type + char junk[8]; + stream.Read(junk, 8); + + AP4_UI32 data; + stream.ReadUI24(data); + + // fscod + switch ((data>>22) & 0x3) { + case 0: + m_SampleRate = 48000; + break; + case 1: + m_SampleRate = 44100; + break; + case 2: + m_SampleRate = 32000; + break; + } + + m_SampleRate <<= 16; + + // acmod + switch ((data>>11) & 0x7) { + case 1: + m_ChannelCount = 1; + break; + case 0: + case 2: + m_ChannelCount = 2; + break; + case 3: + case 4: + m_ChannelCount = 3; + break; + case 5: + case 6: + m_ChannelCount = 4; + break; + case 7: + m_ChannelCount = 5; + break; + } + + // lfeon + if (((data>>10) & 0x1) == 1) + m_ChannelCount++; + + return AP4_SUCCESS; + +} + +AP4_Size +AP4_AC3SampleEntry::GetFieldsSize() +{ + return AP4_AudioSampleEntry::GetFieldsSize() + 11; +} +// <== End patch MPC
\ No newline at end of file diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleEntry.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleEntry.h new file mode 100644 index 000000000..f11a3506c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleEntry.h @@ -0,0 +1,479 @@ +/***************************************************************** +| +| AP4 - sample entries +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_SAMPLE_ENTRY_H_ +#define _AP4_SAMPLE_ENTRY_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4List.h" +#include "Ap4Atom.h" +#include "Ap4EsdsAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4ContainerAtom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_SampleDescription; +class AP4_AvccAtom; + +/*---------------------------------------------------------------------- +| AP4_SampleEntry ++---------------------------------------------------------------------*/ +class AP4_SampleEntry : public AP4_ContainerAtom +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_SampleEntry, AP4_ContainerAtom) + + // methods + AP4_SampleEntry(AP4_Atom::Type format, AP4_UI16 data_ref_index = 1); + AP4_SampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + virtual ~AP4_SampleEntry() {} + + AP4_UI16 GetDataReferenceIndex() { return m_DataReferenceIndex; } + virtual AP4_Result Write(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + virtual AP4_SampleDescription* ToSampleDescription(); + + // AP4_AtomParent methods + virtual void OnChildChanged(AP4_Atom* child); + + protected: + // constructor + AP4_SampleEntry(AP4_Atom::Type format, AP4_Size size); + + // methods + virtual void Read(AP4_ByteStream& stream, AP4_AtomFactory& atom_factory); + virtual AP4_Size GetFieldsSize(); + virtual AP4_Result ReadFields(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + + // members + AP4_UI08 m_Reserved1[6]; // = 0 + AP4_UI16 m_DataReferenceIndex; +}; + +/*---------------------------------------------------------------------- +| AP4_UnknownSampleEntry ++---------------------------------------------------------------------*/ +class AP4_UnknownSampleEntry : public AP4_SampleEntry +{ + public: + // this constructor takes ownership of the atom passed to it + AP4_UnknownSampleEntry(AP4_Atom::Type type, AP4_Size size, AP4_ByteStream& stream); + + // AP4_SampleEntry methods + virtual AP4_SampleDescription* ToSampleDescription(); + + // accessors + const AP4_DataBuffer& GetPayload() { return m_Payload; } + + protected: + // methods + virtual AP4_Size GetFieldsSize(); + virtual AP4_Result ReadFields(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // members + AP4_DataBuffer m_Payload; +}; + +/*---------------------------------------------------------------------- +| AP4_AudioSampleEntry ++---------------------------------------------------------------------*/ +class AP4_AudioSampleEntry : public AP4_SampleEntry +{ +public: + // methods + AP4_AudioSampleEntry(AP4_Atom::Type format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count); + AP4_AudioSampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // accessors + AP4_UI32 GetSampleRate(); + AP4_UI16 GetSampleSize() { return m_SampleSize; } + AP4_UI16 GetChannelCount(); + // ==> Start patch MPC + AP4_UI32 GetBytesPerFrame() { return m_QtV1BytesPerFrame; }; + AP4_UI32 GetSamplesPerPacket(){ return m_QtV1SamplesPerPacket; } + // <== End patch MPC + + // methods + AP4_SampleDescription* ToSampleDescription(); + +protected: + // methods + virtual AP4_Size GetFieldsSize(); + virtual AP4_Result ReadFields(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + + // members + AP4_UI16 m_QtVersion; // 0, 1 or 2 + AP4_UI16 m_QtRevision; // 0 + AP4_UI32 m_QtVendor; // 0 + AP4_UI16 m_ChannelCount; + AP4_UI16 m_SampleSize; + AP4_UI16 m_QtCompressionId; // 0 or -2 + AP4_UI16 m_QtPacketSize; // always 0 + AP4_UI32 m_SampleRate; // 16.16 fixed point + + AP4_UI32 m_QtV1SamplesPerPacket; + AP4_UI32 m_QtV1BytesPerPacket; + AP4_UI32 m_QtV1BytesPerFrame; + AP4_UI32 m_QtV1BytesPerSample; + + AP4_UI32 m_QtV2StructSize; + double m_QtV2SampleRate64; + AP4_UI32 m_QtV2ChannelCount; + AP4_UI32 m_QtV2Reserved; + AP4_UI32 m_QtV2BitsPerChannel; + AP4_UI32 m_QtV2FormatSpecificFlags; + AP4_UI32 m_QtV2BytesPerAudioPacket; + AP4_UI32 m_QtV2LPCMFramesPerAudioPacket; + AP4_DataBuffer m_QtV2Extension; +}; + +/*---------------------------------------------------------------------- +| AP4_VisualSampleEntry ++---------------------------------------------------------------------*/ +class AP4_VisualSampleEntry : public AP4_SampleEntry +{ +public: + // methods + AP4_VisualSampleEntry(AP4_Atom::Type format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name); + AP4_VisualSampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // accessors + AP4_UI16 GetWidth() { return m_Width; } + AP4_UI16 GetHeight() { return m_Height; } + AP4_UI16 GetHorizResolution(){ return m_HorizResolution; } + AP4_UI16 GetVertResolution() { return m_VertResolution; } + AP4_UI16 GetDepth() { return m_Depth; } + const char* GetCompressorName() { return m_CompressorName.GetChars(); } + + // methods + AP4_SampleDescription* ToSampleDescription(); + +protected: + // methods + virtual AP4_Size GetFieldsSize(); + virtual AP4_Result ReadFields(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + + //members + AP4_UI16 m_Predefined1; // = 0 + AP4_UI16 m_Reserved2; // = 0 + AP4_UI08 m_Predefined2[12]; // = 0 + AP4_UI16 m_Width; + AP4_UI16 m_Height; + AP4_UI32 m_HorizResolution; // = 0x00480000 (72 dpi) + AP4_UI32 m_VertResolution; // = 0x00480000 (72 dpi) + AP4_UI32 m_Reserved3; // = 0 + AP4_UI16 m_FrameCount; // = 1 + AP4_String m_CompressorName; + AP4_UI16 m_Depth; // = 0x0018 + AP4_UI16 m_Predefined3; // = 0xFFFF +}; + +/*---------------------------------------------------------------------- +| AP4_MpegSystemSampleEntry ++---------------------------------------------------------------------*/ +class AP4_MpegSystemSampleEntry : public AP4_SampleEntry +{ +public: + // constructors + AP4_MpegSystemSampleEntry(AP4_UI32 type, + AP4_EsDescriptor* descriptor); + AP4_MpegSystemSampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + AP4_SampleDescription* ToSampleDescription(); +}; + +/*---------------------------------------------------------------------- +| AP4_MpegAudioSampleEntry ++---------------------------------------------------------------------*/ +class AP4_MpegAudioSampleEntry : public AP4_AudioSampleEntry +{ +public: + // constructors + AP4_MpegAudioSampleEntry(AP4_UI32 type, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_EsDescriptor* descriptor); + AP4_MpegAudioSampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + AP4_SampleDescription* ToSampleDescription(); +}; + +/*---------------------------------------------------------------------- +| AP4_MpegVideoSampleEntry ++---------------------------------------------------------------------*/ +class AP4_MpegVideoSampleEntry : public AP4_VisualSampleEntry +{ +public: + // constructors + AP4_MpegVideoSampleEntry(AP4_UI32 type, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_EsDescriptor* descriptor); + AP4_MpegVideoSampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + AP4_SampleDescription* ToSampleDescription(); +}; + +/*---------------------------------------------------------------------- +| AP4_Mp4sSampleEntry ++---------------------------------------------------------------------*/ +class AP4_Mp4sSampleEntry : public AP4_MpegSystemSampleEntry +{ + public: + // constructors + AP4_Mp4sSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + AP4_Mp4sSampleEntry(AP4_EsDescriptor* descriptor); + + // methods + AP4_SampleDescription* ToSampleDescription(); +}; + +/*---------------------------------------------------------------------- +| AP4_Mp4aSampleEntry ++---------------------------------------------------------------------*/ +class AP4_Mp4aSampleEntry : public AP4_MpegAudioSampleEntry +{ + public: + // constructors + AP4_Mp4aSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + AP4_Mp4aSampleEntry(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_EsDescriptor* descriptor); +}; + +/*---------------------------------------------------------------------- +| AP4_Mp4vSampleEntry ++---------------------------------------------------------------------*/ +class AP4_Mp4vSampleEntry : public AP4_MpegVideoSampleEntry +{ + public: + // constructors + AP4_Mp4vSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + AP4_Mp4vSampleEntry(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_EsDescriptor* descriptor); +}; + +/*---------------------------------------------------------------------- +| AP4_Avc1SampleEntry ++---------------------------------------------------------------------*/ +class AP4_Avc1SampleEntry : public AP4_VisualSampleEntry +{ +public: + // constructors + AP4_Avc1SampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + AP4_Avc1SampleEntry(AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + const AP4_AvccAtom& avcc); + + // inherited from AP4_SampleEntry + virtual AP4_SampleDescription* ToSampleDescription(); +}; + +/*---------------------------------------------------------------------- +| AP4_RtpHintSampleEntry ++---------------------------------------------------------------------*/ +class AP4_RtpHintSampleEntry : public AP4_SampleEntry +{ +public: + // methods + AP4_RtpHintSampleEntry(AP4_UI16 hint_track_version, + AP4_UI16 highest_compatible_version, + AP4_UI32 max_packet_size, + AP4_UI32 timescale); + AP4_RtpHintSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + +protected: + // methods + virtual AP4_Size GetFieldsSize(); + virtual AP4_Result ReadFields(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + + // members + AP4_UI16 m_HintTrackVersion; + AP4_UI16 m_HighestCompatibleVersion; + AP4_UI32 m_MaxPacketSize; +}; + +// ==> Start patch MPC +/*---------------------------------------------------------------------- +| AP4_TextSampleEntry ++---------------------------------------------------------------------*/ +class AP4_TextSampleEntry : public AP4_SampleEntry +{ +public: + // methods + AP4_TextSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + virtual ~AP4_TextSampleEntry(); + + struct AP4_TextDescription + { + AP4_UI32 DisplayFlags; + AP4_UI32 TextJustification; + AP4_UI32 BackgroundColor; + struct {AP4_UI16 Top, Left, Bottom, Right;} TextBox; + struct {AP4_UI16 StartChar, EndChar, Ascent; struct {AP4_UI16 Id; AP4_UI08 Face, Size; AP4_UI32 Color;} Font;} Style; + AP4_String DefaultFontName; + }; + + const AP4_TextDescription& GetDescription() const { return m_Description; }; + +protected: + // methods + virtual AP4_Result ReadFields(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + + // members + AP4_TextDescription m_Description; +}; + +/*---------------------------------------------------------------------- +| AP4_Tx3gSampleEntry ++---------------------------------------------------------------------*/ +class AP4_Tx3gSampleEntry : public AP4_SampleEntry +{ +public: + // methods + AP4_Tx3gSampleEntry(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + virtual ~AP4_Tx3gSampleEntry(); + + struct AP4_Tx3gDescription + { + AP4_UI32 DisplayFlags; + AP4_UI08 HorizontalJustification; + AP4_UI08 VerticalJustification; + AP4_UI32 BackgroundColor; + struct {AP4_UI16 Top, Left, Bottom, Right;} TextBox; + struct {AP4_UI16 StartChar, EndChar; struct {AP4_UI16 Id; AP4_UI08 Face, Size; AP4_UI32 Color;} Font;} Style; + }; + + const AP4_Tx3gDescription& GetDescription() const { return m_Description; }; + + AP4_Result GetFontNameById(AP4_Ordinal Id, AP4_String& Name); + +protected: + // methods + virtual AP4_Size GetFieldsSize(); + virtual AP4_Result ReadFields(AP4_ByteStream& stream); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + + // members + AP4_Tx3gDescription m_Description; +}; + + + +/*---------------------------------------------------------------------- +| AP4_AC3SampleEntry ++---------------------------------------------------------------------*/ +class AP4_AC3SampleEntry : public AP4_AudioSampleEntry +{ + public: + // constructors + AP4_AC3SampleEntry(AP4_Atom::Type format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count); + + AP4_AC3SampleEntry(AP4_Atom::Type format, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + +protected: + virtual AP4_Size GetFieldsSize(); + virtual AP4_Result ReadFields(AP4_ByteStream& stream); +}; +// <== End patch MPC + +#endif // _AP4_SAMPLE_ENTRY_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleSource.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleSource.cpp new file mode 100644 index 000000000..a641c6a2d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleSource.cpp @@ -0,0 +1,122 @@ +/***************************************************************** +| +| AP4 - Sample Source Interface +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SampleSource.h" +#include "Ap4Track.h" +#include "Ap4SampleDescription.h" +#include "Ap4DataBuffer.h" + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource ++---------------------------------------------------------------------*/ +AP4_TrackSampleSource::AP4_TrackSampleSource(AP4_Track* track) : + m_Track(track), + m_SampleIndex(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_TrackSampleSource::GetTimeScale() +{ + return m_Track->GetMediaTimeScale(); +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource::GetDurationMs ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_TrackSampleSource::GetDurationMs() +{ + return m_Track->GetDurationMs(); +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource::GetTrackId ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_TrackSampleSource::GetTrackId() +{ + return m_Track->GetId(); +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource::ReadNextSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrackSampleSource::ReadNextSample(AP4_Sample& sample, AP4_DataBuffer& buffer) +{ + AP4_Result result = m_Track->ReadSample(m_SampleIndex, sample, buffer); + if (AP4_SUCCEEDED(result)) ++m_SampleIndex; + return result; +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource::GetNearestSyncSampleIndex ++---------------------------------------------------------------------*/ +AP4_Ordinal +AP4_TrackSampleSource::GetNearestSyncSampleIndex(AP4_Ordinal indx, bool before) +{ + return m_Track->GetNearestSyncSampleIndex(indx, before); +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource::GetSampleIndexForTimeStampMs ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrackSampleSource::GetSampleIndexForTimeStampMs(AP4_UI32 timestamp, AP4_Ordinal& indx) +{ + return m_Track->GetSampleIndexForTimeStampMs(timestamp, indx); +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource::SetSampleIndex ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrackSampleSource::SetSampleIndex(AP4_Ordinal indx) +{ + if (indx >= m_Track->GetSampleCount()) return AP4_ERROR_OUT_OF_RANGE; + m_SampleIndex = indx; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource::GetSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_TrackSampleSource::GetSampleDescription(AP4_Ordinal indx) +{ + return m_Track->GetSampleDescription(indx); +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleSource.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleSource.h new file mode 100644 index 000000000..3f2cd94d2 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleSource.h @@ -0,0 +1,118 @@ +/***************************************************************** +| +| AP4 - Sample Source Interface +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_SAMPLE_SOURCE_H_ +#define _AP4_SAMPLE_SOURCE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_Sample; +class AP4_SampleDescription; +class AP4_Track; +class AP4_DataBuffer; + +/*---------------------------------------------------------------------- +| AP4_SampleSource ++---------------------------------------------------------------------*/ +class AP4_SampleSource +{ +public: + virtual ~AP4_SampleSource() {} + + /** + * Return the timscale of the sample's media + */ + virtual AP4_UI32 GetTimeScale() = 0; + + /** + * Return the duration in milliseconds + */ + virtual AP4_UI32 GetDurationMs() = 0; + + /** + * Return the track ID associated with this source, or 0 if there is + * no track ID associated with it. + */ + virtual AP4_UI32 GetTrackId() = 0; + + /** + * Read the next sample from the source + */ + virtual AP4_Result ReadNextSample(AP4_Sample& sample, AP4_DataBuffer& buffer) = 0; + + /** + * Return the index of the nearest sync sample from a given sample index. + */ + virtual AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal indx, bool before=true) = 0; + + /** + * Return the sample index given a timestamp in milliseconds + */ + virtual AP4_Result GetSampleIndexForTimeStampMs(AP4_UI32 timestamp, AP4_Ordinal& indx) = 0; + + /** + * Seek to a specific sample index. + */ + virtual AP4_Result SetSampleIndex(AP4_Ordinal indx) = 0; + + /** + * Return a sample description by index. + * Returns NULL if there is no sample description with the requested index. + */ + virtual AP4_SampleDescription* GetSampleDescription(AP4_Ordinal indx) = 0; +}; + +/*---------------------------------------------------------------------- +| AP4_TrackSampleSource ++---------------------------------------------------------------------*/ +class AP4_TrackSampleSource : public AP4_SampleSource +{ +public: + AP4_TrackSampleSource(AP4_Track* track); + + virtual AP4_UI32 GetTimeScale(); + virtual AP4_UI32 GetDurationMs(); + virtual AP4_UI32 GetTrackId(); + virtual AP4_Result ReadNextSample(AP4_Sample& sample, AP4_DataBuffer& buffer); + virtual AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal indx, bool before=true); + virtual AP4_Result GetSampleIndexForTimeStampMs(AP4_UI32 timestamp, AP4_Ordinal& indx); + virtual AP4_Result SetSampleIndex(AP4_Ordinal indx); + virtual AP4_SampleDescription* GetSampleDescription(AP4_Ordinal indx); + +private: + AP4_Track* m_Track; + AP4_Ordinal m_SampleIndex; +}; + +#endif // _AP4_SAMPLE_SOURCE_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleTable.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleTable.cpp new file mode 100644 index 000000000..3f892d2a9 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleTable.cpp @@ -0,0 +1,209 @@ +/*****************************************************************
+|
+| AP4 - Sample Table Interface
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4SampleTable.h"
+#include "Ap4ContainerAtom.h"
+#include "Ap4StsdAtom.h"
+#include "Ap4StszAtom.h"
+#include "Ap4StscAtom.h"
+#include "Ap4StcoAtom.h"
+#include "Ap4Co64Atom.h"
+#include "Ap4SttsAtom.h"
+#include "Ap4StssAtom.h"
+#include "Ap4CttsAtom.h"
+#include "Ap4Sample.h"
+
+/*----------------------------------------------------------------------
+| AP4_SampleTable::GenerateStblAtom
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SampleTable::GenerateStblAtom(AP4_ContainerAtom*& stbl)
+{
+ // create the stbl container
+ stbl = new AP4_ContainerAtom(AP4_ATOM_TYPE_STBL);
+
+ // create the stsd atom
+ AP4_StsdAtom* stsd = new AP4_StsdAtom(this);
+
+ // create the stsz atom
+ AP4_StszAtom* stsz = new AP4_StszAtom();
+
+ // create the stsc atom
+ AP4_StscAtom* stsc = new AP4_StscAtom();
+
+ // create the stts atom
+ AP4_SttsAtom* stts = new AP4_SttsAtom();
+
+ // create the stss atom
+ AP4_StssAtom* stss = new AP4_StssAtom();
+
+ // declare the ctts atom (may be created later)
+ AP4_CttsAtom* ctts = NULL;
+
+ // start chunk table
+ AP4_Ordinal current_chunk_index = 0;
+ AP4_Size current_chunk_size = 0;
+ AP4_Position current_chunk_offset = 0;
+ AP4_Cardinal current_samples_in_chunk = 0;
+ AP4_Ordinal current_sample_description_index = 0;
+ AP4_UI32 current_duration = 0;
+ AP4_Cardinal current_duration_run = 0;
+ AP4_UI32 current_cts_delta = 0;
+ AP4_Cardinal current_cts_delta_run = 0;
+ AP4_Array<AP4_Position> chunk_offsets;
+
+ // process all the samples
+ bool all_samples_are_sync = false;
+ AP4_Cardinal sample_count = GetSampleCount();
+ for (AP4_Ordinal i=0; i<sample_count; i++) {
+ AP4_Sample sample;
+ GetSample(i, sample);
+
+ // update DTS table
+ AP4_UI32 new_duration = sample.GetDuration();
+ if (new_duration != current_duration && current_duration_run != 0) {
+ // emit a new stts entry
+ stts->AddEntry(current_duration_run, current_duration);
+
+ // reset the run count
+ current_duration_run = 0;
+ }
+ ++current_duration_run;
+ current_duration = new_duration;
+
+ // update CTS table
+ AP4_UI32 new_cts_delta = sample.GetCtsDelta();
+ if (new_cts_delta != current_cts_delta && current_cts_delta_run != 0) {
+ // create a ctts atom if we don't have one
+ if (ctts == NULL) ctts = new AP4_CttsAtom();
+
+ //emit a new ctts entry
+ ctts->AddEntry(current_cts_delta_run, current_cts_delta);
+
+ // reset the run count
+ current_cts_delta_run = 0;
+ }
+ ++current_cts_delta_run;
+ current_cts_delta = new_cts_delta;
+
+ // add an entry into the stsz atom
+ stsz->AddEntry(sample.GetSize());
+
+ // update the sync sample table
+ if (sample.IsSync()) {
+ stss->AddEntry(i+1);
+ if (i==0) all_samples_are_sync = true;
+ } else {
+ all_samples_are_sync = false;
+ }
+
+ // see in which chunk this sample is
+ AP4_Ordinal chunk_index = 0;
+ AP4_Ordinal position_in_chunk = 0;
+ AP4_Result result = GetSampleChunkPosition(i, chunk_index, position_in_chunk);
+ if (AP4_SUCCEEDED(result)) {
+ if (chunk_index != current_chunk_index && current_samples_in_chunk != 0) {
+ // new chunk
+ chunk_offsets.Append(current_chunk_offset);
+ current_chunk_offset += current_chunk_size;
+
+ stsc->AddEntry(1,
+ current_samples_in_chunk,
+ current_sample_description_index+1);
+
+ current_samples_in_chunk = 0;
+ current_chunk_size = 0;
+ }
+ current_chunk_index = chunk_index;
+ }
+
+ // store the sample description index
+ current_sample_description_index = sample.GetDescriptionIndex();
+
+ // adjust the current chunk info
+ current_chunk_size += sample.GetSize();
+ ++current_samples_in_chunk;
+ }
+
+ // finish the stts table
+ stts->AddEntry(current_duration_run, current_duration);
+
+ // finish the ctts table if we have one
+ if (ctts) {
+ AP4_ASSERT(current_cts_delta_run != 0);
+
+ // add a ctts entry
+ ctts->AddEntry(current_cts_delta_run, current_cts_delta);
+ }
+
+ // process any unfinished chunk
+ if (current_samples_in_chunk != 0) {
+ // new chunk
+ chunk_offsets.Append(current_chunk_offset);
+ stsc->AddEntry(1,
+ current_samples_in_chunk,
+ current_sample_description_index+1);
+ }
+
+ // attach the children of stbl
+ stbl->AddChild(stsd);
+ stbl->AddChild(stsz);
+ stbl->AddChild(stsc);
+ stbl->AddChild(stts);
+ if (ctts) stbl->AddChild(ctts);
+ if (!all_samples_are_sync && stss->GetEntries().ItemCount() != 0) {
+ stbl->AddChild(stss);
+ } else {
+ delete stss;
+ }
+
+ // see if we need a co64 or an stco atom
+ AP4_Size chunk_count = chunk_offsets.ItemCount();
+ if (current_chunk_offset <= 0xFFFFFFFF) {
+ // make an array of 32-bit entries
+ AP4_UI32* chunk_offsets_32 = new AP4_UI32[chunk_count];
+ for (unsigned int i=0; i<chunk_count; i++) {
+ chunk_offsets_32[i] = (AP4_UI32)chunk_offsets[i];
+ }
+ // create the stco atom
+ AP4_StcoAtom* stco = new AP4_StcoAtom(&chunk_offsets_32[0], chunk_count);
+ stbl->AddChild(stco);
+
+ delete[] chunk_offsets_32;
+ } else {
+ // create the co64 atom
+ AP4_Co64Atom* co64 = new AP4_Co64Atom(&chunk_offsets[0], chunk_count);
+ stbl->AddChild(co64);
+ }
+
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleTable.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleTable.h new file mode 100644 index 000000000..45a6c7bb0 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SampleTable.h @@ -0,0 +1,66 @@ +/***************************************************************** +| +| AP4 - Sample Table Interface +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_SAMPLE_TABLE_H_ +#define _AP4_SAMPLE_TABLE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_Sample; +class AP4_ContainerAtom; +class AP4_SampleDescription; + +/*---------------------------------------------------------------------- +| AP4_SampleTable ++---------------------------------------------------------------------*/ +class AP4_SampleTable { +public: + // constructors and destructor + virtual ~AP4_SampleTable() {}; + + // methods + virtual AP4_Result GenerateStblAtom(AP4_ContainerAtom*& stbl); + virtual AP4_Result GetSample(AP4_Ordinal sample_index, AP4_Sample& sample) = 0; + virtual AP4_Cardinal GetSampleCount() = 0; + virtual AP4_Result GetSampleChunkPosition(AP4_Ordinal sample_index, + AP4_Ordinal& chunk_index, + AP4_Ordinal& position_in_chunk) = 0; + virtual AP4_Cardinal GetSampleDescriptionCount() = 0; + virtual AP4_SampleDescription* GetSampleDescription(AP4_Ordinal index) = 0; + virtual AP4_Result GetSampleIndexForTimeStamp(AP4_UI64 ts, + AP4_Ordinal& index) = 0; + virtual AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal index, bool before=true) = 0; +}; + +#endif // _AP4_SAMPLE_TABLE_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SchmAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SchmAtom.cpp new file mode 100644 index 000000000..767e59368 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SchmAtom.cpp @@ -0,0 +1,173 @@ +/***************************************************************** +| +| AP4 - schm Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SchmAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_SchmAtom) + +/*---------------------------------------------------------------------- +| AP4_SchmAtom::Create ++---------------------------------------------------------------------*/ +AP4_SchmAtom* +AP4_SchmAtom::Create(AP4_Size size, + AP4_Array<AP4_Atom::Type>* context, + AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + if (size < AP4_FULL_ATOM_HEADER_SIZE+6) return NULL; + + // check the context to see if this is a short form atom or not + bool short_form = false; + if (size < AP4_FULL_ATOM_HEADER_SIZE+8) short_form = true; + if (context) { + AP4_Size context_depth = context->ItemCount(); + if (context_depth >= 2 && + (*context)[context_depth-2] == AP4_ATOM_TYPE('m','r','l','n')) { + short_form = true; + } + } + + return new AP4_SchmAtom(size, version, flags, short_form, stream); +} + +/*---------------------------------------------------------------------- +| AP4_SchmAtom::AP4_SchmAtom ++---------------------------------------------------------------------*/ +AP4_SchmAtom::AP4_SchmAtom(AP4_UI32 scheme_type, + AP4_UI32 scheme_version, + const char* scheme_uri, + bool short_form) : + AP4_Atom(AP4_ATOM_TYPE_SCHM, AP4_FULL_ATOM_HEADER_SIZE+4+(short_form?2:4), 0, 0), + m_AtomHasShortForm(short_form), + m_SchemeType(scheme_type), + m_SchemeVersion(scheme_version) +{ + if (scheme_uri) { + m_SchemeUri = scheme_uri; + m_Flags = 1; + m_Size32 += m_SchemeUri.GetLength()+1; + } +} + +/*---------------------------------------------------------------------- +| AP4_SchmAtom::AP4_SchmAtom ++---------------------------------------------------------------------*/ +AP4_SchmAtom::AP4_SchmAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + bool short_form, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_SCHM, size, version, flags), + m_AtomHasShortForm(short_form) +{ + stream.ReadUI32(m_SchemeType); + if (short_form) { + AP4_UI16 short_version; + stream.ReadUI16(short_version); + m_SchemeVersion = short_version; + } else { + stream.ReadUI32(m_SchemeVersion); + } + if (m_Flags & 1) { + int str_size = size-(AP4_FULL_ATOM_HEADER_SIZE+8); + if (str_size > 0) { + char* str = new char[str_size]; + stream.Read(str, str_size); + str[str_size-1] = '\0'; // force null-termination + m_SchemeUri = str; + delete[] str; + } + } +} + +/*---------------------------------------------------------------------- +| AP4_SchmAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SchmAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // scheme type + result = stream.WriteUI32(m_SchemeType); + if (AP4_FAILED(result)) return result; + + // scheme version + if (m_AtomHasShortForm) { + result = stream.WriteUI16((AP4_UI16)m_SchemeVersion); + if (AP4_FAILED(result)) return result; + } else { + result = stream.WriteUI32(m_SchemeVersion); + if (AP4_FAILED(result)) return result; + } + + // uri if needed + if (m_Flags & 1) { + result = stream.Write(m_SchemeUri.GetChars(), m_SchemeUri.GetLength()+1); + if (AP4_FAILED(result)) return result; + + // pad with zeros if necessary + AP4_Size fields_size = 4+(m_AtomHasShortForm?2:4); + AP4_Size padding = m_Size32-(AP4_FULL_ATOM_HEADER_SIZE+fields_size+m_SchemeUri.GetLength()+1); + while (padding--) stream.WriteUI08(0); + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_SchmAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SchmAtom::InspectFields(AP4_AtomInspector& inspector) +{ + char st[5]; + AP4_FormatFourChars(st, m_SchemeType); + inspector.AddField("scheme_type", st); + if (m_AtomHasShortForm) { + inspector.AddField("scheme_version (short)", m_SchemeVersion); + } else { + inspector.AddField("scheme_version", m_SchemeVersion); + } + if (m_Flags & 1) { + inspector.AddField("scheme_uri", m_SchemeUri.GetChars()); + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SchmAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SchmAtom.h new file mode 100644 index 000000000..3b2a065db --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SchmAtom.h @@ -0,0 +1,89 @@ +/***************************************************************** +| +| AP4 - schm Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_SCHM_ATOM_H_ +#define _AP4_SCHM_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4String.h" +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_SchmAtom ++---------------------------------------------------------------------*/ +class AP4_SchmAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_SchmAtom, AP4_Atom) + + // class methods + static AP4_SchmAtom* Create(AP4_Size size, + AP4_Array<AP4_Atom::Type>* context, + AP4_ByteStream& stream); + + // constructors + AP4_SchmAtom(AP4_UI32 scheme_type, + AP4_UI32 scheme_version, + const char* scheme_uri = NULL, + bool short_form = false); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetSchemeType() { return m_SchemeType; } + AP4_UI32 GetSchemeVersion() { return m_SchemeVersion; } + AP4_String& GetSchemeUri() { return m_SchemeUri; } + +private: + // methods + AP4_SchmAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + bool short_form, + AP4_ByteStream& stream); + + // members + bool m_AtomHasShortForm; // for versions of this where the version + // field is only 16 bits + AP4_UI32 m_SchemeType; + AP4_UI32 m_SchemeVersion; + AP4_String m_SchemeUri; +}; + +#endif // _AP4_SCHM_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SdpAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SdpAtom.cpp new file mode 100644 index 000000000..56237781e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SdpAtom.cpp @@ -0,0 +1,99 @@ +/***************************************************************** +| +| AP4 - sdp Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SdpAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + + +/*---------------------------------------------------------------------- +| AP4_SdpAtom::AP4_SdpAtom ++---------------------------------------------------------------------*/ +AP4_SdpAtom::AP4_SdpAtom(const char* sdp_text) : + AP4_Atom(AP4_ATOM_TYPE_SDP_, AP4_ATOM_HEADER_SIZE), + m_SdpText(sdp_text) +{ + m_Size32 += m_SdpText.GetLength()+1; +} + +/*---------------------------------------------------------------------- +| AP4_SdpAtom::AP4_SdpAtom ++---------------------------------------------------------------------*/ +AP4_SdpAtom::AP4_SdpAtom(AP4_UI32 size, AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_SDP_, size) +{ + // sdptext + AP4_Size str_size = size-AP4_ATOM_HEADER_SIZE; + if (str_size > 0) { + char* str = new char[str_size+1]; + stream.Read(str, str_size); + str[str_size] = '\0'; // force null-termination + m_SdpText = str; + delete[] str; + } +} + +/*---------------------------------------------------------------------- +| AP4_SdpAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SdpAtom::WriteFields(AP4_ByteStream& stream) +{ + // sdptext + AP4_Result result = stream.Write(m_SdpText.GetChars(), m_SdpText.GetLength()); + if (AP4_FAILED(result)) return result; + + // pad with zeros if necessary + AP4_Size padding = m_Size32-(AP4_ATOM_HEADER_SIZE+m_SdpText.GetLength()); + while (padding--) stream.WriteUI08(0); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SdpAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SdpAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("sdp_text", m_SdpText.GetChars()); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SdpAtom::GetSdpText ++---------------------------------------------------------------------*/ +const AP4_String& +AP4_SdpAtom::GetSdpText() const +{ + return m_SdpText; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SdpAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SdpAtom.h new file mode 100644 index 000000000..421a73b12 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SdpAtom.h @@ -0,0 +1,71 @@ +/***************************************************************** +| +| AP4 - sdp Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_SDP_ATOM_H_ +#define _AP4_SDP_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4List.h" +#include "Ap4Atom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_SdpAtom ++---------------------------------------------------------------------*/ +class AP4_SdpAtom : public AP4_Atom +{ +public: + // class methods + static AP4_SdpAtom* Create(AP4_Size size, AP4_ByteStream& stream) { + return new AP4_SdpAtom(size, stream); + } + + // methods + AP4_SdpAtom(const char* sdp_text); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + const AP4_String& GetSdpText() const; + +private: + // methods + AP4_SdpAtom(AP4_UI32 size, AP4_ByteStream& stream); + + // members + AP4_String m_SdpText; +}; + +#endif // _AP4_SDP_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SmhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SmhdAtom.cpp new file mode 100644 index 000000000..88052ced1 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SmhdAtom.cpp @@ -0,0 +1,100 @@ +/***************************************************************** +| +| AP4 - smhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SmhdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_SmhdAtom::Create ++---------------------------------------------------------------------*/ +AP4_SmhdAtom* +AP4_SmhdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_SmhdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_SmhdAtom::AP4_SmhdAtom ++---------------------------------------------------------------------*/ +AP4_SmhdAtom::AP4_SmhdAtom(AP4_UI16 balance) : + AP4_Atom(AP4_ATOM_TYPE_SMHD, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0), + m_Balance(balance) +{ + m_Reserved = 0; +} + +/*---------------------------------------------------------------------- +| AP4_SmhdAtom::AP4_SmhdAtom ++---------------------------------------------------------------------*/ +AP4_SmhdAtom::AP4_SmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_SMHD, size, version, flags) +{ + stream.ReadUI16(m_Balance); + stream.ReadUI16(m_Reserved); +} + +/*---------------------------------------------------------------------- +| AP4_SmhdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SmhdAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // balance + result = stream.WriteUI16(m_Balance); + if (AP4_FAILED(result)) return result; + + // reserved + result = stream.WriteUI16(m_Reserved); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SmhdAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SmhdAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("balance", m_Balance); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SmhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SmhdAtom.h new file mode 100644 index 000000000..8d6269b5b --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SmhdAtom.h @@ -0,0 +1,64 @@ +/***************************************************************** +| +| AP4 - smhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_SMHD_ATOM_H_ +#define _AP4_SMHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_SmhdAtom ++---------------------------------------------------------------------*/ +class AP4_SmhdAtom : public AP4_Atom +{ +public: + // class methods + static AP4_SmhdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_SmhdAtom(AP4_UI16 balance); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_SmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI16 m_Balance; + AP4_UI16 m_Reserved; +}; + +#endif // _AP4_SMHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StcoAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StcoAtom.cpp new file mode 100644 index 000000000..4ed8fe1f3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StcoAtom.cpp @@ -0,0 +1,185 @@ +/***************************************************************** +| +| AP4 - stco Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4StcoAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_StcoAtom) + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::Create ++---------------------------------------------------------------------*/ +AP4_StcoAtom* +AP4_StcoAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_StcoAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::AP4_StcoAtom ++---------------------------------------------------------------------*/ +AP4_StcoAtom::AP4_StcoAtom(AP4_UI32* entries, AP4_UI32 entry_count) : +AP4_Atom(AP4_ATOM_TYPE_STCO, + AP4_FULL_ATOM_HEADER_SIZE+4+entry_count*4, + 0, 0), + m_Entries(new AP4_UI32[entry_count]), + m_EntryCount(entry_count) +{ + AP4_CopyMemory(m_Entries, entries, m_EntryCount*4); +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::AP4_StcoAtom ++---------------------------------------------------------------------*/ +AP4_StcoAtom::AP4_StcoAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_STCO, size, version, flags) +{ + stream.ReadUI32(m_EntryCount); + if (m_EntryCount > (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4) { + m_EntryCount = (size-AP4_FULL_ATOM_HEADER_SIZE-4)/4; + } + m_Entries = new AP4_UI32[m_EntryCount]; + unsigned char* buffer = new unsigned char[m_EntryCount*4]; + AP4_Result result = stream.Read(buffer, m_EntryCount*4); + if (AP4_FAILED(result)) { + delete[] buffer; + return; + } + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + m_Entries[i] = AP4_BytesToUInt32BE(&buffer[i*4]); + } + delete[] buffer; +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::~AP4_StcoAtom ++---------------------------------------------------------------------*/ +AP4_StcoAtom::~AP4_StcoAtom() +{ + delete[] m_Entries; +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::GetChunkOffset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StcoAtom::GetChunkOffset(AP4_Ordinal chunk, AP4_UI32& chunk_offset) +{ + // check the bounds + if (chunk > m_EntryCount || chunk == 0) { + return AP4_ERROR_OUT_OF_RANGE; + } + + // get the chunk offset + chunk_offset = m_Entries[chunk - 1]; // m_Entries is zero index based + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::SetChunkOffset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StcoAtom::SetChunkOffset(AP4_Ordinal chunk, AP4_UI32 chunk_offset) +{ + // check the bounds + if (chunk > m_EntryCount || chunk == 0) { + return AP4_ERROR_OUT_OF_RANGE; + } + + // get the chunk offset + m_Entries[chunk - 1] = chunk_offset; // m_Entries is zero index based + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::AdjustChunkOffsets ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StcoAtom::AdjustChunkOffsets(int delta) +{ + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + m_Entries[i] += delta; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StcoAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // entry count + result = stream.WriteUI32(m_EntryCount); + if (AP4_FAILED(result)) return result; + + // entries + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + result = stream.WriteUI32(m_Entries[i]); + if (AP4_FAILED(result)) return result; + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_StcoAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StcoAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("entry_count", m_EntryCount); + if (inspector.GetVerbosity() >= 1) { + char header[32]; + for (AP4_Ordinal i=0; i<m_EntryCount; i++) { + AP4_FormatString(header, sizeof(header), "entry %8d", i); + inspector.AddField(header, m_Entries[i]); + } + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StcoAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StcoAtom.h new file mode 100644 index 000000000..7fdaea4cc --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StcoAtom.h @@ -0,0 +1,72 @@ +/***************************************************************** +| +| AP4 - stco Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_STCO_ATOM_H_ +#define _AP4_STCO_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_StcoAtom ++---------------------------------------------------------------------*/ +class AP4_StcoAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_StcoAtom, AP4_Atom) + + // class methods + static AP4_StcoAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_StcoAtom(AP4_UI32* offsets, AP4_UI32 offset_count); + ~AP4_StcoAtom(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + AP4_Cardinal GetChunkCount() { return m_EntryCount; } + AP4_UI32* GetChunkOffsets() { return m_Entries; } + AP4_Result GetChunkOffset(AP4_Ordinal chunk, AP4_UI32& chunk_offset); + AP4_Result SetChunkOffset(AP4_Ordinal chunk, AP4_UI32 chunk_offset); + AP4_Result AdjustChunkOffsets(int delta); + +private: + // methods + AP4_StcoAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI32* m_Entries; + AP4_UI32 m_EntryCount; +}; + +#endif // _AP4_STCO_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4String.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4String.cpp new file mode 100644 index 000000000..f93422416 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4String.cpp @@ -0,0 +1,181 @@ +/***************************************************************** +| +| AP4 - Strings +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4String.h" +#include "Ap4Types.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_String::EmptyString ++---------------------------------------------------------------------*/ +char AP4_String::EmptyString = 0; + +/*---------------------------------------------------------------------- +| AP4_String::AP4_String ++---------------------------------------------------------------------*/ +AP4_String::AP4_String() : m_Chars(&EmptyString), m_Length(0) {} + +/*---------------------------------------------------------------------- +| AP4_String::AP4_String ++---------------------------------------------------------------------*/ +AP4_String::AP4_String(const char* s) { + if (s == NULL) { + m_Chars = &EmptyString; + m_Length = 0; + return; + } + m_Length = (AP4_Size)AP4_StringLength(s); + m_Chars = new char[m_Length+1]; + AP4_CopyMemory(m_Chars, s, m_Length+1); +} + +/*---------------------------------------------------------------------- +| AP4_String::AP4_String ++---------------------------------------------------------------------*/ +AP4_String::AP4_String(const char* s, AP4_Size size) : + m_Chars(new char[size+1]), + m_Length(size) +{ + m_Chars[size] = 0; + AP4_CopyMemory(m_Chars, s, size); +} + +/*---------------------------------------------------------------------- +| AP4_String::AP4_String ++---------------------------------------------------------------------*/ +AP4_String::AP4_String(const AP4_String& s) { + m_Length = s.m_Length; + m_Chars = new char[m_Length+1]; + AP4_CopyMemory(m_Chars, s.m_Chars, m_Length+1); +} + +/*---------------------------------------------------------------------- +| AP4_String::AP4_String ++---------------------------------------------------------------------*/ +AP4_String::AP4_String(AP4_Size size) { + m_Length = size; + m_Chars = new char[m_Length+1]; + for (unsigned int i=0; i<size+1; i++) m_Chars[i] = 0; +} + +/*---------------------------------------------------------------------- +| AP4_String::~AP4_String ++---------------------------------------------------------------------*/ +AP4_String::~AP4_String() +{ + if (m_Chars != &EmptyString) delete[] m_Chars; +} + +/*---------------------------------------------------------------------- +| AP4_String::operator= ++---------------------------------------------------------------------*/ +const AP4_String& +AP4_String::operator=(const AP4_String& s) +{ + if (&s == this) return s; + if (m_Chars != &EmptyString) delete[] m_Chars; + m_Length = s.m_Length; + m_Chars = new char[m_Length+1]; + AP4_CopyMemory(m_Chars, s.m_Chars, m_Length+1); + + return *this; +} + +/*---------------------------------------------------------------------- +| AP4_String::operator= ++---------------------------------------------------------------------*/ +const AP4_String& +AP4_String::operator=(const char* s) +{ + if (s == NULL) { + if (m_Chars != &EmptyString) delete[] m_Chars; + m_Chars = &EmptyString; + m_Length = 0; + } else { + Assign(s, (AP4_Size)AP4_StringLength(s)); + } + + return *this; +} + +/*---------------------------------------------------------------------- +| AP4_String::operator== ++---------------------------------------------------------------------*/ +bool +AP4_String::operator==(const AP4_String& s) const +{ + if (m_Length != s.m_Length) return false; + for (unsigned int i=0; i<m_Length; i++) { + if (m_Chars[i] != s.m_Chars[i]) return false; + } + return true; +} + + +/*---------------------------------------------------------------------- +| AP4_String::operator== ++---------------------------------------------------------------------*/ +bool +AP4_String::operator==(const char* s) const +{ + AP4_Size s_length = (AP4_Size)AP4_StringLength(s); + if (m_Length != s_length) return false; + for (unsigned int i=0; i<s_length; i++) { + if (m_Chars[i] != s[i]) return false; + } + return true; +} + +/*---------------------------------------------------------------------- +| AP4_String::Assign ++---------------------------------------------------------------------*/ +void +AP4_String::Assign(const char* s, AP4_Size size) +{ + if (m_Chars != &EmptyString) delete[] m_Chars; + m_Length = size; + m_Chars = new char[m_Length+1]; + AP4_CopyMemory(m_Chars, s, m_Length); + m_Chars[size] = '\0'; +} + +/*---------------------------------------------------------------------- +| AP4_String::Find ++---------------------------------------------------------------------*/ +int +AP4_String::Find(char c, unsigned int start) const +{ + const char* chars = GetChars(); + for (unsigned int i=start; i<m_Length; i++) { + if (chars[i] == c) return i; + } + return -1; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4String.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4String.h new file mode 100644 index 000000000..f1d81ef06 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4String.h @@ -0,0 +1,81 @@ +/***************************************************************** +| +| AP4 - Strings +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_STRING_H_ +#define _AP4_STRING_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Config.h" +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| AP4_String ++---------------------------------------------------------------------*/ +class AP4_String +{ +public: + // constructors + AP4_String(); + AP4_String(const char* s); + AP4_String(const char* s, AP4_Size size); + AP4_String(const AP4_String& s); + explicit AP4_String(AP4_Size size); + + // destructor + ~AP4_String(); + + // operators + const AP4_String& operator=(const AP4_String& s); + const AP4_String& operator=(const char* s); + char operator[](unsigned int index) const { + return m_Chars[index]; + } + bool operator==(const AP4_String& s) const; + bool operator!=(const AP4_String& s) const { return !(*this == s); } + bool operator==(const char* s) const; + bool operator!=(const char* s) const { return !(*this == s); } + + // methods + AP4_Size GetLength() const { return m_Length; } + const char* GetChars() const { return m_Chars; } + char* UseChars() { return m_Chars; } + void Assign(const char* chars, AP4_Size size); + int Find(char c, unsigned int start = 0) const; + +private: + // class members + static char EmptyString; + + // members + char* m_Chars; + AP4_Size m_Length; +}; + +#endif // _AP4_STRING_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StscAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StscAtom.cpp new file mode 100644 index 000000000..7e108f285 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StscAtom.cpp @@ -0,0 +1,252 @@ + /***************************************************************** +| +| AP4 - stsc Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4StscAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_StscAtom) + +/*---------------------------------------------------------------------- +| AP4_StscAtom::Create ++---------------------------------------------------------------------*/ +AP4_StscAtom* +AP4_StscAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_StscAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_StscAtom::AP4_StscAtom ++---------------------------------------------------------------------*/ +AP4_StscAtom::AP4_StscAtom() : + AP4_Atom(AP4_ATOM_TYPE_STSC, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0), + m_CachedChunkGroup(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_StscAtom::AP4_StscAtom ++---------------------------------------------------------------------*/ +AP4_StscAtom::AP4_StscAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_STSC, size, version, flags), + m_CachedChunkGroup(0) +{ + AP4_UI32 first_sample = 1; + AP4_UI32 entry_count; + stream.ReadUI32(entry_count); + m_Entries.SetItemCount(entry_count); + unsigned char* buffer = new unsigned char[entry_count*12]; + AP4_Result result = stream.Read(buffer, entry_count*12); + if (AP4_FAILED(result)) { + delete[] buffer; + return; + } + for (unsigned int i=0; i<entry_count; i++) { + AP4_UI32 first_chunk = AP4_BytesToUInt32BE(&buffer[i*12 ]); + AP4_UI32 samples_per_chunk = AP4_BytesToUInt32BE(&buffer[i*12+4]); + AP4_UI32 sample_description_index = AP4_BytesToUInt32BE(&buffer[i*12+8]); + if (i) { + AP4_Ordinal prev = i-1; + m_Entries[prev].m_ChunkCount = first_chunk-m_Entries[prev].m_FirstChunk; + first_sample += m_Entries[prev].m_ChunkCount * m_Entries[prev].m_SamplesPerChunk; + } + m_Entries[i].m_ChunkCount = 0; // not known yet + m_Entries[i].m_FirstChunk = first_chunk; + m_Entries[i].m_FirstSample = first_sample; + m_Entries[i].m_SamplesPerChunk = samples_per_chunk; + m_Entries[i].m_SampleDescriptionIndex = sample_description_index; + } + delete[] buffer; +} + +/*---------------------------------------------------------------------- +| AP4_StscAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StscAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // entry count + AP4_Cardinal entry_count = m_Entries.ItemCount(); + result = stream.WriteUI32(entry_count); + + // entries + for (AP4_Ordinal i=0; i<entry_count; i++) { + stream.WriteUI32(m_Entries[i].m_FirstChunk); + if (AP4_FAILED(result)) return result; + stream.WriteUI32(m_Entries[i].m_SamplesPerChunk); + if (AP4_FAILED(result)) return result; + stream.WriteUI32(m_Entries[i].m_SampleDescriptionIndex); + if (AP4_FAILED(result)) return result; + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_StscAtom::AddEntry ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StscAtom::AddEntry(AP4_Cardinal chunk_count, + AP4_Cardinal samples_per_chunk, + AP4_Ordinal sample_description_index) +{ + AP4_Ordinal first_chunk; + AP4_Ordinal first_sample; + AP4_Cardinal entry_count = m_Entries.ItemCount(); + if (entry_count == 0) { + // first entry + first_chunk = 1; + first_sample = 1; + } else { + first_chunk = m_Entries[entry_count-1].m_FirstChunk+ + m_Entries[entry_count-1].m_ChunkCount; + first_sample = m_Entries[entry_count-1].m_FirstSample+ + m_Entries[entry_count-1].m_ChunkCount* + m_Entries[entry_count-1].m_SamplesPerChunk; + } + m_Entries.Append(AP4_StscTableEntry(first_chunk, first_sample, chunk_count, samples_per_chunk, sample_description_index)); + + // update the atom size + m_Size32 += 12; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_StscAtom::GetChunkForSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StscAtom::GetChunkForSample(AP4_Ordinal sample, + AP4_Ordinal& chunk, + AP4_Ordinal& skip, + AP4_Ordinal& sample_description_index) +{ + // preconditions + AP4_ASSERT(sample > 0); + + // decide whether to start the search from the cached index + // or from the start + AP4_Ordinal group; + if (m_CachedChunkGroup < m_Entries.ItemCount() && + m_Entries[m_CachedChunkGroup].m_FirstSample <= sample) { + group = m_CachedChunkGroup; + } else { + group = 0; + } + + // find which group of chunk contains this one + while (group < m_Entries.ItemCount()) { + AP4_Cardinal sample_count = + m_Entries[group].m_ChunkCount*m_Entries[group].m_SamplesPerChunk; + if (sample_count == 0) { + // unlimited samples in this group (last group) + if (m_Entries[group].m_FirstSample > sample) { + // something is wrong + return AP4_ERROR_INVALID_FORMAT; + } + } else { + // normal group + if (m_Entries[group].m_FirstSample + sample_count <= sample) { + // the sample is not in this group + group++; + continue; + } + } + + // the sample is in this group + if (m_Entries[group].m_SamplesPerChunk == 0) { + // something is wrong + return AP4_ERROR_INVALID_FORMAT; + } + unsigned int chunk_offset = + ((sample-m_Entries[group].m_FirstSample) / + m_Entries[group].m_SamplesPerChunk); + chunk = m_Entries[group].m_FirstChunk + chunk_offset; + skip = sample - + (m_Entries[group].m_FirstSample + + m_Entries[group].m_SamplesPerChunk*chunk_offset); + sample_description_index = m_Entries[group].m_SampleDescriptionIndex; + + // cache the result (to accelerate finding the right group + // next time around) + m_CachedChunkGroup = group; + + return AP4_SUCCESS; + } + + // chunk not found + chunk = 0; + skip = 0; + sample_description_index = 0; + return AP4_ERROR_OUT_OF_RANGE; +} + +/*---------------------------------------------------------------------- +| AP4_StscAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StscAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("entry_count", m_Entries.ItemCount()); + + // dump table entries + if (inspector.GetVerbosity() >= 1) { + char header[32]; + char value[256]; + for (unsigned int i=0; i<m_Entries.ItemCount(); i++) { + AP4_FormatString(header, sizeof(header), "entry %8d", i); + AP4_FormatString(value, sizeof(value), + "first_chunk=%d, first_sample*=%d, chunk_count*=%d, samples_per_chunk=%d, sample_desc_index=%d", + m_Entries[i].m_FirstChunk, + m_Entries[i].m_FirstSample, + m_Entries[i].m_ChunkCount, + m_Entries[i].m_SamplesPerChunk, + m_Entries[i].m_SampleDescriptionIndex); + inspector.AddField(header, value); + } + } + + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StscAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StscAtom.h new file mode 100644 index 000000000..23def43b7 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StscAtom.h @@ -0,0 +1,116 @@ +/***************************************************************** +| +| AP4 - stsc Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_STSC_ATOM_H_ +#define _AP4_STSC_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| AP4_StscTableEntry ++---------------------------------------------------------------------*/ +class AP4_StscTableEntry { + public: + AP4_StscTableEntry() : + m_FirstChunk(0), + m_FirstSample(0), + m_ChunkCount(0), + m_SamplesPerChunk(0), + m_SampleDescriptionIndex(0) {} + AP4_StscTableEntry(AP4_Ordinal first_chunk, + AP4_Ordinal first_sample, + AP4_Cardinal samples_per_chunk, + AP4_Ordinal sample_description_index) : + m_FirstChunk(first_chunk), + m_FirstSample(first_sample), + m_ChunkCount(0), + m_SamplesPerChunk(samples_per_chunk), + m_SampleDescriptionIndex(sample_description_index) {} + AP4_StscTableEntry(AP4_Ordinal first_chunk, + AP4_Ordinal first_sample, + AP4_Cardinal chunk_count, + AP4_Cardinal samples_per_chunk, + AP4_Ordinal sample_description_index) : + m_FirstChunk(first_chunk), + m_FirstSample(first_sample), + m_ChunkCount(chunk_count), + m_SamplesPerChunk(samples_per_chunk), + m_SampleDescriptionIndex(sample_description_index) {} + AP4_Ordinal m_FirstChunk; + AP4_Ordinal m_FirstSample; // computed (not in file) + AP4_Cardinal m_ChunkCount; // computed (not in file) + AP4_Cardinal m_SamplesPerChunk; + AP4_Ordinal m_SampleDescriptionIndex; +}; + +/*---------------------------------------------------------------------- +| AP4_StscAtom ++---------------------------------------------------------------------*/ +class AP4_StscAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_StscAtom, AP4_Atom) + + // class methods + static AP4_StscAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_StscAtom(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result GetChunkForSample(AP4_Ordinal sample, + AP4_Ordinal& chunk, + AP4_Ordinal& skip, + AP4_Ordinal& sample_description_index); + virtual AP4_Result AddEntry(AP4_Cardinal chunk_count, + AP4_Cardinal samples_per_chunk, + AP4_Ordinal sample_description_index); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // ==> Start patch MPC + // FIXME
+ friend class AP4_AtomSampleTable;
+ // <== End patch MPC
+ +private: + // methods + AP4_StscAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_Array<AP4_StscTableEntry> m_Entries; + AP4_Ordinal m_CachedChunkGroup; +}; + +#endif // _AP4_STSC_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StsdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StsdAtom.cpp new file mode 100644 index 000000000..3ce86da1b --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StsdAtom.cpp @@ -0,0 +1,222 @@ +/*****************************************************************
+|
+| AP4 - stsd Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4StsdAtom.h"
+#include "Ap4AtomFactory.h"
+#include "Ap4Utils.h"
+#include "Ap4SampleEntry.h"
+#include "Ap4SampleTable.h"
+#include "Ap4SampleDescription.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_StsdAtom)
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::Create
++---------------------------------------------------------------------*/
+AP4_StsdAtom*
+AP4_StsdAtom::Create(AP4_Size size,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version != 0) return NULL;
+ return new AP4_StsdAtom(size, version, flags, stream, atom_factory);
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::AP4_StsdAtom
++---------------------------------------------------------------------*/
+AP4_StsdAtom::AP4_StsdAtom(AP4_SampleTable* sample_table) :
+ AP4_ContainerAtom(AP4_ATOM_TYPE_STSD, (AP4_UI32)0, (AP4_UI32)0)
+{
+ m_Size32 += 4;
+ AP4_Cardinal sample_description_count = sample_table->GetSampleDescriptionCount();
+ m_SampleDescriptions.EnsureCapacity(sample_description_count);
+ for (AP4_Ordinal i=0; i<sample_description_count; i++) {
+ // clear the cache entry
+ m_SampleDescriptions.Append(NULL);
+
+ // create an entry for the description
+ AP4_SampleDescription* sample_description = sample_table->GetSampleDescription(i);
+ AP4_Atom* entry = sample_description->ToAtom();
+ m_Children.Add(entry);
+
+ // update the size
+ m_Size32 += (AP4_UI32)entry->GetSize();
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::AP4_StsdAtom
++---------------------------------------------------------------------*/
+AP4_StsdAtom::AP4_StsdAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream,
+ AP4_AtomFactory& atom_factory) :
+ AP4_ContainerAtom(AP4_ATOM_TYPE_STSD, size, false, version, flags)
+{
+ // read the number of entries
+ AP4_UI32 entry_count;
+ stream.ReadUI32(entry_count);
+
+ // save and switch the factory's context
+ atom_factory.PushContext(m_Type);
+
+ // read all entries
+ AP4_LargeSize bytes_available = size-AP4_FULL_ATOM_HEADER_SIZE-4;
+ for (unsigned int i=0; i<entry_count; i++) {
+ AP4_Atom* atom;
+ if (AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(stream,
+ bytes_available,
+ atom))) {
+ atom->SetParent(this);
+ m_Children.Add(atom);
+ }
+ }
+
+ // restore the saved context
+ atom_factory.PopContext();
+
+ // initialize the sample description cache
+ m_SampleDescriptions.EnsureCapacity(m_Children.ItemCount());
+ for (AP4_Ordinal i=0; i<m_Children.ItemCount(); i++) {
+ m_SampleDescriptions.Append(NULL);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::~AP4_StsdAtom
++---------------------------------------------------------------------*/
+AP4_StsdAtom::~AP4_StsdAtom()
+{
+ for (AP4_Ordinal i=0; i<m_SampleDescriptions.ItemCount(); i++) {
+ delete m_SampleDescriptions[i];
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_StsdAtom::WriteFields(AP4_ByteStream& stream)
+{
+ AP4_Result result;
+
+ // entry count
+ result = stream.WriteUI32(m_Children.ItemCount());
+ if (AP4_FAILED(result)) return result;
+
+ // entries
+ return m_Children.Apply(AP4_AtomListWriter(stream));
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::OnChildChanged
++---------------------------------------------------------------------*/
+void
+AP4_StsdAtom::OnChildChanged(AP4_Atom*)
+{
+ // remcompute our size
+ AP4_UI64 size = GetHeaderSize()+4;
+ m_Children.Apply(AP4_AtomSizeAdder(size));
+ m_Size32 = (AP4_UI32)size;
+
+ // update our parent
+ if (m_Parent) m_Parent->OnChildChanged(this);
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::GetSampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_StsdAtom::GetSampleDescription(AP4_Ordinal index)
+{
+ // check index
+ if (index >= m_Children.ItemCount()) return NULL;
+
+ // return the description if we already have it in the internal table
+ if (m_SampleDescriptions[index]) return m_SampleDescriptions[index];
+
+ // create and cache a sample description for this entry
+ AP4_Atom* entry;
+ m_Children.Get(index, entry);
+ AP4_SampleEntry* sample_entry = AP4_DYNAMIC_CAST(AP4_SampleEntry, entry);
+ if (sample_entry == NULL) {
+ m_SampleDescriptions[index] = new AP4_UnknownSampleDescription(entry);
+ } else {
+ m_SampleDescriptions[index] = sample_entry->ToSampleDescription();
+ }
+ return m_SampleDescriptions[index];
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::GetSampleEntry
++---------------------------------------------------------------------*/
+AP4_SampleEntry*
+AP4_StsdAtom::GetSampleEntry(AP4_Ordinal index)
+{
+ // check index
+ if (index >= m_Children.ItemCount()) return NULL;
+
+ // return the sample entry
+ AP4_Atom* entry;
+ m_Children.Get(index, entry);
+ return AP4_DYNAMIC_CAST(AP4_SampleEntry, entry);
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::GetSampleDescriptionCount
++---------------------------------------------------------------------*/
+AP4_Cardinal
+AP4_StsdAtom::GetSampleDescriptionCount()
+{
+ return m_Children.ItemCount();
+}
+
+/*----------------------------------------------------------------------
+| AP4_StsdAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_StsdAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("entry-count", m_Children.ItemCount());
+
+ // inspect children
+ m_Children.Apply(AP4_AtomListInspector(inspector));
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StsdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StsdAtom.h new file mode 100644 index 000000000..8a5013a72 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StsdAtom.h @@ -0,0 +1,84 @@ +/***************************************************************** +| +| AP4 - stsd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_STSD_ATOM_H_ +#define _AP4_STSD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Array.h" +#include "Ap4ContainerAtom.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_SampleTable; +class AP4_SampleDescription; +class AP4_SampleEntry; + +/*---------------------------------------------------------------------- +| AP4_StsdAtom ++---------------------------------------------------------------------*/ +class AP4_StsdAtom : public AP4_ContainerAtom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_StsdAtom, AP4_ContainerAtom) + + // class methods + static AP4_StsdAtom* Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // methods + AP4_StsdAtom(AP4_SampleTable* sample_table); + ~AP4_StsdAtom(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Cardinal GetSampleDescriptionCount(); + virtual AP4_SampleDescription* GetSampleDescription(AP4_Ordinal index); + virtual AP4_SampleEntry* GetSampleEntry(AP4_Ordinal index); + + // AP4_AtomParent methods + void OnChildChanged(AP4_Atom* child); + +private: + // methods + AP4_StsdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // members + AP4_Array<AP4_SampleDescription*> m_SampleDescriptions; +}; + +#endif // _AP4_STSD_ATOM_H_ + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StssAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StssAtom.cpp new file mode 100644 index 000000000..23d06f82d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StssAtom.cpp @@ -0,0 +1,155 @@ +/***************************************************************** +| +| AP4 - stss Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4StssAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_StssAtom) + +/*---------------------------------------------------------------------- +| AP4_StssAtom::Create ++---------------------------------------------------------------------*/ +AP4_StssAtom* +AP4_StssAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_StssAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_StssAtom::AP4_StssAtom ++---------------------------------------------------------------------*/ +AP4_StssAtom::AP4_StssAtom() : + AP4_Atom(AP4_ATOM_TYPE_STSS, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_StssAtom::AP4_StssAtom ++---------------------------------------------------------------------*/ +AP4_StssAtom::AP4_StssAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_STSS, size, version, flags), + m_LookupCache(0) +{ + AP4_UI32 entry_count; + stream.ReadUI32(entry_count); + while (entry_count--) { + AP4_UI32 entry_sample_index; + if (stream.ReadUI32(entry_sample_index) == AP4_SUCCESS) { + m_Entries.Append(entry_sample_index); + } + } +} + +/*---------------------------------------------------------------------- +| AP4_StssAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StssAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // entry count + AP4_Cardinal entry_count = m_Entries.ItemCount(); + result = stream.WriteUI32(entry_count); + if (AP4_FAILED(result)) return result; + + // entries + for (AP4_Ordinal i=0; i<entry_count; i++) { + result = stream.WriteUI32(m_Entries[i]); + if (AP4_FAILED(result)) return result; + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_StssAtom::AddEntry ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StssAtom::AddEntry(AP4_UI32 sample) +{ + m_Entries.Append(sample); + m_Size32 += 4; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_StssAtom::IsSampleSync ++---------------------------------------------------------------------*/ +bool +AP4_StssAtom::IsSampleSync(AP4_Ordinal sample) +{ + unsigned int entry_index = 0; + + // check bounds + if (sample == 0 || m_Entries.ItemCount() == 0) return false; + + // see if we can start from the cached index + if (m_Entries[m_LookupCache] <= sample) { + entry_index = m_LookupCache; + } + + // do a linear search + while (entry_index < m_Entries.ItemCount() && + m_Entries[entry_index] <= sample) { + if (m_Entries[entry_index] == sample) { + m_LookupCache = entry_index; + return true; + } + entry_index++; + } + + return false; +} + +/*---------------------------------------------------------------------- +| AP4_StssAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StssAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("entry_count", m_Entries.ItemCount()); + + return AP4_SUCCESS; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StssAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StssAtom.h new file mode 100644 index 000000000..0384cb6a3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StssAtom.h @@ -0,0 +1,72 @@ +/***************************************************************** +| +| AP4 - stss Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_STSS_ATOM_H_ +#define _AP4_STSS_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Array.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_StssAtom ++---------------------------------------------------------------------*/ +class AP4_StssAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_StssAtom, AP4_Atom) + + // class methods + static AP4_StssAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // constructor + AP4_StssAtom(); + + // methods + // methods + const AP4_Array<AP4_UI32>& GetEntries() { return m_Entries; } + AP4_Result AddEntry(AP4_UI32 sample); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual bool IsSampleSync(AP4_Ordinal sample); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_StssAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_Array<AP4_UI32> m_Entries; + AP4_Ordinal m_LookupCache; +}; + +#endif // _AP4_STSS_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StszAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StszAtom.cpp new file mode 100644 index 000000000..97dfc9f91 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StszAtom.cpp @@ -0,0 +1,211 @@ +/***************************************************************** +| +| AP4 - stsz Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4StszAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_StszAtom) + +/*---------------------------------------------------------------------- +| AP4_StszAtom::Create ++---------------------------------------------------------------------*/ +AP4_StszAtom* +AP4_StszAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_StszAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::AP4_StszAtom ++---------------------------------------------------------------------*/ +AP4_StszAtom::AP4_StszAtom() : + AP4_Atom(AP4_ATOM_TYPE_STSZ, AP4_FULL_ATOM_HEADER_SIZE+8, 0, 0), + m_SampleSize(0), + m_SampleCount(0) +{ +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::AP4_StszAtom ++---------------------------------------------------------------------*/ +AP4_StszAtom::AP4_StszAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_STSZ, size, version, flags) +{ + stream.ReadUI32(m_SampleSize); + stream.ReadUI32(m_SampleCount); + if (m_SampleSize == 0) { // means that the samples have different sizes + unsigned long sample_count = m_SampleCount; + m_Entries.SetItemCount(sample_count); + unsigned char* buffer = new unsigned char[sample_count*4]; + AP4_Result result = stream.Read(buffer, sample_count*4); + if (AP4_FAILED(result)) { + delete[] buffer; + return; + } + for (unsigned int i=0; i<sample_count; i++) { + m_Entries[i] = AP4_BytesToUInt32BE(&buffer[i*4]); + } + delete[] buffer; + } +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StszAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // sample size + result = stream.WriteUI32(m_SampleSize); + if (AP4_FAILED(result)) return result; + + // sample count + result = stream.WriteUI32(m_SampleCount); + if (AP4_FAILED(result)) return result; + + // entries if needed (the samples have different sizes) + if (m_SampleSize == 0) { + for (AP4_UI32 i=0; i<m_SampleCount; i++) { + result = stream.WriteUI32(m_Entries[i]); + if (AP4_FAILED(result)) return result; + } + } + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::GetSampleCount ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_StszAtom::GetSampleCount() +{ + return m_SampleCount; +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::GetSampleSize ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StszAtom::GetSampleSize(AP4_Ordinal sample, AP4_Size& sample_size) +{ + // check the sample index + if (sample > m_SampleCount || sample == 0) { + sample_size = 0; + return AP4_ERROR_OUT_OF_RANGE; + } else { + // find the size + if (m_SampleSize != 0) { // constant size + sample_size = m_SampleSize; + } else { + sample_size = m_Entries[sample - 1]; + } + return AP4_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::SetSampleSize ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StszAtom::SetSampleSize(AP4_Ordinal sample, AP4_Size sample_size) +{ + // check the sample index + if (sample > m_SampleCount || sample == 0) { + return AP4_ERROR_OUT_OF_RANGE; + } else { + if (m_Entries.ItemCount() == 0) { + // all samples must have the same size + if (sample_size != m_SampleSize) { + // not the same + if (sample == 1) { + // if this is the first sample, update the global size + m_SampleSize = sample_size; + return AP4_SUCCESS; + } else { + // can't have different sizes + return AP4_ERROR_INVALID_PARAMETERS; + } + } + } else { + // each sample has a different size + m_Entries[sample - 1] = sample_size; + } + + return AP4_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::AddEntry ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StszAtom::AddEntry(AP4_UI32 size) +{ + m_Entries.Append(size); + m_SampleCount++; + m_Size32 += 4; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_StszAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_StszAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("sample_size", m_SampleSize); + inspector.AddField("sample_count", m_Entries.ItemCount()); + + if (inspector.GetVerbosity() >= 2) { + char header[32]; + for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) { + AP4_FormatString(header, sizeof(header), "entry %8d", i); + inspector.AddField(header, m_Entries[i]); + } + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StszAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StszAtom.h new file mode 100644 index 000000000..70bfa9309 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4StszAtom.h @@ -0,0 +1,88 @@ +/***************************************************************** +| +| AP4 - stsz Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_STSZ_ATOM_H_ +#define _AP4_STSZ_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Array.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_StszAtom ++---------------------------------------------------------------------*/ +class AP4_StszAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_StszAtom, AP4_Atom) + + // class methods + static AP4_StszAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_StszAtom(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_UI32 GetSampleCount(); + virtual AP4_Result GetSampleSize(AP4_Ordinal sample, + AP4_Size& sample_size); + /** + * Set the sample size. + * @param sample 1-based index of a sample. + * @param sample_size Size of the sample. + * If this table represents a global-size table (one where there are + * no individual entries for each sample, but all sample have the same + * size = m_SampleSize), then calling this method with sample=1 will update + * the global size, and calling with sample>1 will check that + * the value of sample_size is the same as the global size m_SampleSize. + */ + virtual AP4_Result SetSampleSize(AP4_Ordinal sample, + AP4_Size sample_size); + virtual AP4_Result AddEntry(AP4_UI32 size); + + // ==> Start patch MPC + // FIXME
+ friend class AP4_AtomSampleTable;
+ // <== End patch MPC
+ +private: + // methods + AP4_StszAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI32 m_SampleSize; + AP4_UI32 m_SampleCount; + AP4_Array<AP4_UI32> m_Entries; +}; + +#endif // _AP4_STSZ_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SttsAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SttsAtom.cpp new file mode 100644 index 000000000..15a8d8418 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SttsAtom.cpp @@ -0,0 +1,236 @@ +/***************************************************************** +| +| AP4 - stts Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4SttsAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_SttsAtom) + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::Create ++---------------------------------------------------------------------*/ +AP4_SttsAtom* +AP4_SttsAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_SttsAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::AP4_SttsAtom ++---------------------------------------------------------------------*/ +AP4_SttsAtom::AP4_SttsAtom() : + AP4_Atom(AP4_ATOM_TYPE_STTS, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0) +{ + m_LookupCache.entry_index = 0; + m_LookupCache.sample = 0; + m_LookupCache.dts = 0; +} + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::AP4_SttsAtom ++---------------------------------------------------------------------*/ +AP4_SttsAtom::AP4_SttsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_STTS, size, version, flags) +{ + m_LookupCache.entry_index = 0; + m_LookupCache.sample = 0; + m_LookupCache.dts = 0; + + AP4_UI32 entry_count; + stream.ReadUI32(entry_count); + while (entry_count--) { + AP4_UI32 sample_count; + AP4_UI32 sample_duration; + if (stream.ReadUI32(sample_count) == AP4_SUCCESS && + stream.ReadUI32(sample_duration) == AP4_SUCCESS) { + m_Entries.Append(AP4_SttsTableEntry(sample_count, + sample_duration)); + } + } +} + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::GetDts ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SttsAtom::GetDts(AP4_Ordinal sample, AP4_UI64& dts, AP4_UI32* duration) +{ + // default value + dts = 0; + if (duration) *duration = 0; + + // sample indexes start at 1 + if (sample == 0) return AP4_ERROR_OUT_OF_RANGE; + + // check the lookup cache + AP4_Ordinal lookup_start = 0; + AP4_Ordinal sample_start = 0; + AP4_UI64 dts_start = 0; + if (sample >= m_LookupCache.sample) { + // start from the cached entry + lookup_start = m_LookupCache.entry_index; + sample_start = m_LookupCache.sample; + dts_start = m_LookupCache.dts; + } + + // look from the last known point + for (AP4_Ordinal i = lookup_start; i < m_Entries.ItemCount(); i++) { + AP4_SttsTableEntry& entry = m_Entries[i]; + + // check if we have reached the sample + if (sample <= sample_start+entry.m_SampleCount) { + // we are within the sample range for the current entry + dts = dts_start + (AP4_UI64)(sample-1 - sample_start) * (AP4_UI64)entry.m_SampleDuration; + if (duration) *duration = entry.m_SampleDuration; + + // update the lookup cache + m_LookupCache.entry_index = i; + m_LookupCache.sample = sample_start; + m_LookupCache.dts = dts_start; + + return AP4_SUCCESS; + } + + // update the sample and dts bases + sample_start += entry.m_SampleCount; + dts_start += entry.m_SampleCount*entry.m_SampleDuration; + } + + // sample is greater than the number of samples + return AP4_ERROR_OUT_OF_RANGE; +} + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::AddEntry ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SttsAtom::AddEntry(AP4_UI32 sample_count, AP4_UI32 sample_duration) +{ + m_Entries.Append(AP4_SttsTableEntry(sample_count, sample_duration)); + m_Size32 += 8; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SttsAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // write the entry count + AP4_Cardinal entry_count = m_Entries.ItemCount(); + result = stream.WriteUI32(entry_count); + if (AP4_FAILED(result)) return result; + + // write the entries + for (AP4_Ordinal i=0; i<entry_count; i++) { + // sample count + result = stream.WriteUI32(m_Entries[i].m_SampleCount); + if (AP4_FAILED(result)) return result; + + // time offset + result = stream.WriteUI32(m_Entries[i].m_SampleDuration); + if (AP4_FAILED(result)) return result; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::GetSampleIndexForTimeStamp ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SttsAtom::GetSampleIndexForTimeStamp(AP4_UI64 ts, + AP4_Ordinal& sample_index) +{ + // init + AP4_Cardinal entry_count = m_Entries.ItemCount(); + AP4_UI64 accumulated = 0; + sample_index = 0; + + for (AP4_Ordinal i=0; i<entry_count; i++) { + AP4_UI64 next_accumulated = + accumulated + + (AP4_UI64)m_Entries[i].m_SampleCount * + (AP4_UI64)m_Entries[i].m_SampleDuration; + + // check if the ts is in the range of this entry + if (ts < next_accumulated) { + sample_index += (AP4_UI32)((ts - accumulated) / m_Entries[i].m_SampleDuration); + return AP4_SUCCESS; + } + + // update accumulated and sample + accumulated = next_accumulated; + sample_index += m_Entries[i].m_SampleCount; + } + + // ts not in range of the table + return AP4_FAILURE; +} + +/*---------------------------------------------------------------------- +| AP4_SttsAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_SttsAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("entry_count", m_Entries.ItemCount()); + + if (inspector.GetVerbosity() >= 1) { + char header[32]; + char value[256]; + for (AP4_Ordinal i=0; i<m_Entries.ItemCount(); i++) { + AP4_FormatString(header, sizeof(header), "entry %8d", i); + AP4_FormatString(value, sizeof(value), + "sample_count=%d, sample_duration=%d", + m_Entries[i].m_SampleCount, + m_Entries[i].m_SampleDuration); + inspector.AddField(header, value); + } + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SttsAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SttsAtom.h new file mode 100644 index 000000000..def7acc37 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SttsAtom.h @@ -0,0 +1,96 @@ +/***************************************************************** +| +| AP4 - stts Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_STTS_ATOM_H_ +#define _AP4_STTS_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Array.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_SttsTableEntry ++---------------------------------------------------------------------*/ +class AP4_SttsTableEntry { + public: + AP4_SttsTableEntry() : + m_SampleCount(0), + m_SampleDuration(0) {} + AP4_SttsTableEntry(AP4_UI32 sample_count, + AP4_UI32 sample_duration) : + m_SampleCount(sample_count), + m_SampleDuration(sample_duration) {} + + AP4_UI32 m_SampleCount; + AP4_UI32 m_SampleDuration; +}; + +/*---------------------------------------------------------------------- +| AP4_SttsAtom ++---------------------------------------------------------------------*/ +class AP4_SttsAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_SttsAtom, AP4_Atom) + + // class methods + static AP4_SttsAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_SttsAtom(); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result GetDts(AP4_Ordinal sample, AP4_UI64& dts, AP4_UI32* duration = NULL); + virtual AP4_Result AddEntry(AP4_UI32 sample_count, AP4_UI32 sample_duration); + virtual AP4_Result GetSampleIndexForTimeStamp(AP4_UI64 ts, + AP4_Ordinal& sample_index); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // ==> Start patch MPC + // FIXME
+ friend class AP4_AtomSampleTable;
+ // <== End patch MPC
+ +private: + // methods + AP4_SttsAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_Array<AP4_SttsTableEntry> m_Entries; + struct { + AP4_Ordinal entry_index; + AP4_Ordinal sample; + AP4_UI64 dts; + } m_LookupCache; +}; + +#endif // _AP4_STTS_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SyntheticSampleTable.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SyntheticSampleTable.cpp new file mode 100644 index 000000000..b2926e4ac --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SyntheticSampleTable.cpp @@ -0,0 +1,228 @@ +/*****************************************************************
+|
+| AP4 - Synthetic Sample Table
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4Atom.h"
+#include "Ap4SyntheticSampleTable.h"
+#include "Ap4Sample.h"
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::AP4_SyntheticSampleTable()
++---------------------------------------------------------------------*/
+AP4_SyntheticSampleTable::AP4_SyntheticSampleTable(AP4_Cardinal chunk_size) :
+ m_ChunkSize(chunk_size?chunk_size:AP4_SYNTHETIC_SAMPLE_TABLE_DEFAULT_CHUNK_SIZE)
+{
+ m_LookupCache.m_Sample = 0;
+ m_LookupCache.m_Chunk = 0;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::~AP4_SyntheticSampleTable()
++---------------------------------------------------------------------*/
+AP4_SyntheticSampleTable::~AP4_SyntheticSampleTable()
+{
+ m_SampleDescriptions.DeleteReferences();
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::GetSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SyntheticSampleTable::GetSample(AP4_Ordinal sample_index, AP4_Sample& sample)
+{
+ if (sample_index >= m_Samples.ItemCount()) return AP4_ERROR_OUT_OF_RANGE;
+
+ sample = m_Samples[sample_index];
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::GetSampleCount
++---------------------------------------------------------------------*/
+AP4_Cardinal
+AP4_SyntheticSampleTable::GetSampleCount()
+{
+ return m_Samples.ItemCount();
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::GetSampleChunkPosition
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SyntheticSampleTable::GetSampleChunkPosition(
+ AP4_Ordinal sample_index,
+ AP4_Ordinal& chunk_index,
+ AP4_Ordinal& position_in_chunk)
+{
+ // default values
+ chunk_index = 0;
+ position_in_chunk = 0;
+
+ // check parameters
+ if (sample_index >= m_Samples.ItemCount()) return AP4_ERROR_OUT_OF_RANGE;
+
+ // look for the chunk
+ AP4_Ordinal sample_cursor = 0;
+ AP4_Ordinal chunk_cursor = 0;
+ if (sample_index >= m_LookupCache.m_Sample) {
+ sample_cursor = m_LookupCache.m_Sample;
+ chunk_cursor = m_LookupCache.m_Chunk;
+ }
+ for (;
+ chunk_cursor < m_SamplesInChunk.ItemCount();
+ sample_cursor += m_SamplesInChunk[chunk_cursor++]) {
+ if (sample_cursor+m_SamplesInChunk[chunk_cursor] > sample_index) {
+ chunk_index = chunk_cursor;
+ position_in_chunk = sample_index-sample_cursor;
+ m_LookupCache.m_Sample = sample_cursor;
+ m_LookupCache.m_Chunk = chunk_cursor;
+ return AP4_SUCCESS;
+ }
+ }
+
+ return AP4_ERROR_OUT_OF_RANGE;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::GetSampleDescriptionCount
++---------------------------------------------------------------------*/
+AP4_Cardinal
+AP4_SyntheticSampleTable::GetSampleDescriptionCount()
+{
+ return m_SampleDescriptions.ItemCount();
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::GetSampleDescription
++---------------------------------------------------------------------*/
+AP4_SampleDescription*
+AP4_SyntheticSampleTable::GetSampleDescription(AP4_Ordinal index)
+{
+ SampleDescriptionHolder* holder;
+ if (AP4_SUCCEEDED(m_SampleDescriptions.Get(index, holder))) {
+ return holder->m_SampleDescription;
+ } else {
+ return NULL;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::AddSampleDescription
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SyntheticSampleTable::AddSampleDescription(AP4_SampleDescription* description,
+ bool transfer_ownership)
+{
+ return m_SampleDescriptions.Add(new SampleDescriptionHolder(description, transfer_ownership));
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::AddSample
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SyntheticSampleTable::AddSample(AP4_ByteStream& data_stream,
+ AP4_Position offset,
+ AP4_Size size,
+ AP4_UI32 duration,
+ AP4_Ordinal description_index,
+ AP4_UI64 dts,
+ AP4_UI32 cts_delta,
+ bool sync)
+{
+ // decide if we need to start a new chunk or increment the last one
+ if (m_SamplesInChunk.ItemCount() == 0 ||
+ m_SamplesInChunk[m_SamplesInChunk.ItemCount()-1] >= m_ChunkSize ||
+ m_Samples.ItemCount() == 0 ||
+ m_Samples[m_Samples.ItemCount()-1].GetDescriptionIndex() != description_index) {
+ m_SamplesInChunk.Append(1);
+ } else {
+ ++m_SamplesInChunk[m_SamplesInChunk.ItemCount()-1];
+ }
+
+ // compute the timestamps
+ if (m_Samples.ItemCount() > 0) {
+ AP4_Sample* prev_sample = &m_Samples[m_Samples.ItemCount()-1];
+ if (dts == 0) {
+ if (prev_sample->GetDuration() == 0) {
+ // can't compute the DTS for this sample
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+ dts = prev_sample->GetDts()+prev_sample->GetDuration();
+ } else {
+ if (prev_sample->GetDuration() == 0) {
+ // update the previous sample
+ if (dts <= prev_sample->GetDts()) return AP4_ERROR_INVALID_PARAMETERS;
+ prev_sample->SetDuration((AP4_UI32)(dts-prev_sample->GetDts()));
+ } else {
+ if (dts != prev_sample->GetDts()+prev_sample->GetDuration()) {
+ // mismatch
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+ }
+ }
+ }
+
+ // add the sample to the table
+ AP4_Sample sample(data_stream, offset, size, duration, description_index, dts, cts_delta, sync);
+ return m_Samples.Append(sample);
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::GetSampleIndexForTimeStamp
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SyntheticSampleTable::GetSampleIndexForTimeStamp(AP4_UI64 /* ts */,
+ AP4_Ordinal& /* index */)
+{
+ return AP4_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable::GetNearestSyncSampleIndex
++---------------------------------------------------------------------*/
+AP4_Ordinal
+AP4_SyntheticSampleTable::GetNearestSyncSampleIndex(AP4_Ordinal sample_index, bool before)
+{
+ if (before) {
+ for (int i=sample_index; i>=0; i--) {
+ if (m_Samples[i].IsSync()) return i;
+ }
+ // not found?
+ return 0;
+ } else {
+ AP4_Cardinal entry_count = m_Samples.ItemCount();
+ for (unsigned int i=sample_index; i<entry_count; i++) {
+ if (m_Samples[i].IsSync()) return i;
+ }
+ // not found?
+ return m_Samples.ItemCount();
+ }
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SyntheticSampleTable.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SyntheticSampleTable.h new file mode 100644 index 000000000..e54d9074d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4SyntheticSampleTable.h @@ -0,0 +1,144 @@ +/*****************************************************************
+|
+| AP4 - Synthetic Sample Table
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_SYNTHETIC_SAMPLE_TABLE_H_
+#define _AP4_SYNTHETIC_SAMPLE_TABLE_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Array.h"
+#include "Ap4List.h"
+#include "Ap4Sample.h"
+#include "Ap4SampleTable.h"
+#include "Ap4SampleDescription.h"
+
+/*----------------------------------------------------------------------
+| forward declarations
++---------------------------------------------------------------------*/
+class AP4_ByteStream;
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_Cardinal AP4_SYNTHETIC_SAMPLE_TABLE_DEFAULT_CHUNK_SIZE = 10;
+
+/*----------------------------------------------------------------------
+| AP4_SyntheticSampleTable
++---------------------------------------------------------------------*/
+class AP4_SyntheticSampleTable : public AP4_SampleTable
+{
+ public:
+ // methods
+ AP4_SyntheticSampleTable(AP4_Cardinal chunk_size
+ = AP4_SYNTHETIC_SAMPLE_TABLE_DEFAULT_CHUNK_SIZE);
+ virtual ~AP4_SyntheticSampleTable();
+
+ // AP4_SampleTable methods
+ virtual AP4_Result GetSample(AP4_Ordinal index, AP4_Sample& sample);
+ virtual AP4_Cardinal GetSampleCount();
+ virtual AP4_Result GetSampleChunkPosition(AP4_Ordinal sample_index,
+ AP4_Ordinal& chunk_index,
+ AP4_Ordinal& position_in_chunk);
+ virtual AP4_Cardinal GetSampleDescriptionCount();
+ virtual AP4_SampleDescription* GetSampleDescription(AP4_Ordinal index);
+ virtual AP4_Result GetSampleIndexForTimeStamp(AP4_UI64 ts, AP4_Ordinal& index);
+ virtual AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal index, bool before);
+
+ // methods
+ /**
+ * Add a sample description to the sample table.
+ * Each added sample description will have the next available index, starting at 0
+ *
+ * @param description Pointer to the sample description to add
+ * @param transfer_ownership Boolean flag indicating whether the ownership of the
+ * sample description object is transfered to the sample table object (true by default).
+ * If true, the sample table object will own the sample description object, and will
+ * delete it when it is itself deleted. If false, the ownership remains with the caller,
+ * and only a referencing pointer is kept, thus the caller must ensure that the object
+ * is not deleted before the sample table is deleted.
+ */
+ virtual AP4_Result AddSampleDescription(AP4_SampleDescription* description,
+ bool transfer_ownership=true);
+
+ /**
+ * Add a sample to the sample table, where the sample duration is given
+ *
+ * @param data_stream The byte stream that contains the sample data. The sample
+ * object added to the track will keep a reference to that byte stream.
+ * @param offset Position of the first byte of sample data within the stream
+ * @param size Size in bytes of the sample data
+ * @param duration Duration of the sample (in the timescale of the media). This
+ * value can be 0 if the duration is not known. In that case, the next sample
+ * added to the table MUST have a non-zero value for the DTS (decoding timestamp),
+ * which will allow the actual duration of this sample to be computed.
+ * @param description_index Index of the sample description that applies to
+ * this sample (typically 0).
+ * @param dts DTS (decoding timestamp) of the sample. If this value is 0, and there
+ * already are samples in the table, the DTS of the sample will be automatically
+ * computed based on the DTS and duration of the preceding sample. If this value is
+ * not equal to the DTS+duration of the preceding sample, the duration of the
+ * preceding sample is automatically adjusted, unless it has a non-zero value, in which
+ * case AP4_ERROR_INVALID_PARAMETERS is returned.
+ * The DTS of the first sample in the table MUST always be 0.
+ * @param cts_delta Difference between the CTS (composition/display timestamp) and DTS
+ * (decoding timestamp) of the sample (in the timescale of the media)
+ * @param sync Boolean flag indicating whether this is a sync sample or not.
+ */
+ virtual AP4_Result AddSample(AP4_ByteStream& data_stream,
+ AP4_Position offset,
+ AP4_Size size,
+ AP4_UI32 duration,
+ AP4_Ordinal description_index,
+ AP4_UI64 dts,
+ AP4_UI32 cts_delta,
+ bool sync);
+
+private:
+ // classes
+ class SampleDescriptionHolder {
+ public:
+ SampleDescriptionHolder(AP4_SampleDescription* description, bool is_owned) :
+ m_SampleDescription(description), m_IsOwned(is_owned) {}
+ ~SampleDescriptionHolder() { if (m_IsOwned) delete m_SampleDescription; }
+ AP4_SampleDescription* m_SampleDescription;
+ bool m_IsOwned;
+ };
+
+ // members
+ AP4_Array<AP4_Sample> m_Samples;
+ AP4_List<SampleDescriptionHolder> m_SampleDescriptions;
+ AP4_Cardinal m_ChunkSize;
+ AP4_Array<AP4_UI32> m_SamplesInChunk;
+ struct {
+ AP4_Ordinal m_Sample;
+ AP4_Ordinal m_Chunk;
+ } m_LookupCache;
+};
+
+#endif // _AP4_SYNTHETIC_SAMPLE_TABLE_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfhdAtom.cpp new file mode 100644 index 000000000..678e6ccb3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfhdAtom.cpp @@ -0,0 +1,174 @@ +/*****************************************************************
+|
+| AP4 - tfhd Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4TfhdAtom.h"
+#include "Ap4Utils.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TfhdAtom)
+
+/*----------------------------------------------------------------------
+| AP4_TfhdAtom::Create
++---------------------------------------------------------------------*/
+AP4_TfhdAtom*
+AP4_TfhdAtom::Create(AP4_Size size, AP4_ByteStream& stream)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version > 0) return NULL;
+ if (size != ComputeSize(flags)) return NULL;
+ return new AP4_TfhdAtom(size, version, flags, stream);
+}
+
+/*----------------------------------------------------------------------
+| AP4_TfhdAtom::ComputeSize
++---------------------------------------------------------------------*/
+AP4_UI32
+AP4_TfhdAtom::ComputeSize(AP4_UI32 flags)
+{
+ AP4_UI32 size = AP4_FULL_ATOM_HEADER_SIZE+4;
+ if (flags & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) size += 8;
+ if (flags & AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT) size += 4;
+ if (flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT) size += 4;
+ if (flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) size += 4;
+ if (flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT) size += 4;
+ return size;
+}
+
+/*----------------------------------------------------------------------
+| AP4_TfhdAtom::AP4_TfhdAtom
++---------------------------------------------------------------------*/
+AP4_TfhdAtom::AP4_TfhdAtom(AP4_UI32 flags,
+ AP4_UI32 track_id,
+ AP4_UI64 base_data_offset,
+ AP4_UI32 sample_description_index,
+ AP4_UI32 default_sample_duration,
+ AP4_UI32 default_sample_size,
+ AP4_UI32 default_sample_flags) :
+ AP4_Atom(AP4_ATOM_TYPE_TFHD, ComputeSize(flags), 0, flags),
+ m_TrackId(track_id),
+ m_BaseDataOffset(base_data_offset),
+ m_SampleDescriptionIndex(sample_description_index),
+ m_DefaultSampleDuration(default_sample_duration),
+ m_DefaultSampleSize(default_sample_size),
+ m_DefaultSampleFlags(default_sample_flags)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_TfhdAtom::AP4_TfhdAtom
++---------------------------------------------------------------------*/
+AP4_TfhdAtom::AP4_TfhdAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream) :
+ AP4_Atom(AP4_ATOM_TYPE_TFHD, size, version, flags)
+{
+ stream.ReadUI32(m_TrackId);
+ if (flags & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
+ stream.ReadUI64(m_BaseDataOffset);
+ }
+ if (flags & AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT) {
+ stream.ReadUI32(m_SampleDescriptionIndex);
+ }
+ if (flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT) {
+ stream.ReadUI32(m_DefaultSampleDuration);
+ }
+ if (flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) {
+ stream.ReadUI32(m_DefaultSampleSize);
+ }
+ if (flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT) {
+ stream.ReadUI32(m_DefaultSampleFlags);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_TfhdAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_TfhdAtom::WriteFields(AP4_ByteStream& stream)
+{
+ AP4_Result result;
+
+ result = stream.WriteUI32(m_TrackId);
+ if (AP4_FAILED(result)) return result;
+ if (m_Flags & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
+ result = stream.WriteUI64(m_BaseDataOffset);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT) {
+ result = stream.WriteUI32(m_SampleDescriptionIndex);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT) {
+ stream.WriteUI32(m_DefaultSampleDuration);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) {
+ stream.WriteUI32(m_DefaultSampleSize);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT) {
+ stream.WriteUI32(m_DefaultSampleFlags);
+ if (AP4_FAILED(result)) return result;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_TfhdAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_TfhdAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("track ID", m_TrackId);
+ if (m_Flags & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
+ inspector.AddField("base data offset", m_BaseDataOffset);
+ }
+ if (m_Flags & AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT) {
+ inspector.AddField("sample description index", m_SampleDescriptionIndex);
+ }
+ if (m_Flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT) {
+ inspector.AddField("default sample duration", m_DefaultSampleDuration);
+ }
+ if (m_Flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) {
+ inspector.AddField("default sample size", m_DefaultSampleSize);
+ }
+ if (m_Flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT) {
+ inspector.AddField("default sample flags", m_DefaultSampleFlags, AP4_AtomInspector::HINT_HEX );
+ }
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfhdAtom.h new file mode 100644 index 000000000..db0d3f777 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfhdAtom.h @@ -0,0 +1,99 @@ +/*****************************************************************
+|
+| AP4 - tfhd Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_TFHD_ATOM_H_
+#define _AP4_TFHD_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_UI32 AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT = 0x00001;
+const AP4_UI32 AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT = 0x00002;
+const AP4_UI32 AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT = 0x00008;
+const AP4_UI32 AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT = 0x00010;
+const AP4_UI32 AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT = 0x00020;
+const AP4_UI32 AP4_TFHD_FLAG_DURATION_IS_EMPTY = 0x10000;
+
+/*----------------------------------------------------------------------
+| AP4_TfhdAtom
++---------------------------------------------------------------------*/
+class AP4_TfhdAtom : public AP4_Atom
+{
+public:
+ AP4_IMPLEMENT_DYNAMIC_CAST(AP4_TfhdAtom)
+
+ // class methods
+ static AP4_TfhdAtom* Create(AP4_Size size, AP4_ByteStream& stream);
+ static AP4_UI32 ComputeSize(AP4_UI32 flags);
+
+ // methods
+ AP4_TfhdAtom(AP4_UI32 flags,
+ AP4_UI32 track_id,
+ AP4_UI64 base_data_offset,
+ AP4_UI32 sample_description_index,
+ AP4_UI32 default_sample_duration,
+ AP4_UI32 default_sample_size,
+ AP4_UI32 default_sample_flags);
+ virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
+ virtual AP4_Result WriteFields(AP4_ByteStream& stream);
+
+ AP4_UI32 GetTrackId() { return m_TrackId; }
+ void SetTrackId(AP4_UI32 track_id) { m_TrackId = track_id; }
+ AP4_UI64 GetBaseDataOffset() { return m_BaseDataOffset; }
+ void SetBaseDataOffset(AP4_UI64 offset) { m_BaseDataOffset = offset; }
+ AP4_UI32 GetSampleDescriptionIndex() { return m_SampleDescriptionIndex; }
+ void SetSampleDescriptionIndex(AP4_UI32 indx) { m_SampleDescriptionIndex = indx; }
+ AP4_UI32 GetDefaultSampleDuration() { return m_DefaultSampleDuration; }
+ void SetDefaultSampleDuration(AP4_UI32 duration) { m_DefaultSampleDuration = duration; }
+ AP4_UI32 GetDefaultSampleSize() { return m_DefaultSampleSize; }
+ void SetDefaultSampleSize(AP4_UI32 size) { m_DefaultSampleSize = size; }
+ AP4_UI32 GetDefaultSampleFlags() { return m_DefaultSampleFlags; }
+ void SetDefaultSampleFlags(AP4_UI32 flags) { m_DefaultSampleFlags = flags; }
+
+private:
+ // methods
+ AP4_TfhdAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream);
+
+ // members
+ AP4_UI32 m_TrackId;
+ AP4_UI64 m_BaseDataOffset;
+ AP4_UI32 m_SampleDescriptionIndex;
+ AP4_UI32 m_DefaultSampleDuration;
+ AP4_UI32 m_DefaultSampleSize;
+ AP4_UI32 m_DefaultSampleFlags;
+};
+
+#endif // _AP4_TFHD_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfraAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfraAtom.cpp new file mode 100644 index 000000000..1c5437128 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfraAtom.cpp @@ -0,0 +1,298 @@ +/***************************************************************** +| +| AP4 - tfra Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4TfraAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_TfraAtom::Create ++---------------------------------------------------------------------*/ +AP4_TfraAtom* +AP4_TfraAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version = 0; + AP4_UI32 flags = 0; + AP4_Result result = ReadFullHeader(stream, version, flags); + if (AP4_FAILED(result)) return NULL; + if (version > 1) return NULL; + return new AP4_TfraAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_TfraAtom::AP4_TfraAtom ++---------------------------------------------------------------------*/ +AP4_TfraAtom::AP4_TfraAtom() : + AP4_Atom(AP4_ATOM_TYPE_TFRA, AP4_FULL_ATOM_HEADER_SIZE+4+4+4) +{ +} + +/*---------------------------------------------------------------------- +| AP4_TfraAtom::AP4_TfraAtom ++---------------------------------------------------------------------*/ +AP4_TfraAtom::AP4_TfraAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_TFRA, size, version, flags) +{ + stream.ReadUI32(m_TrackId); + AP4_UI32 fields = 0; + stream.ReadUI32(fields); + m_LengthSizeOfTrafNumber = (fields>>4)&3; + m_LengthSizeOfTrunNumber = (fields>>2)&3; + m_LengthSizeOfSampleNumber = (fields )&3; + AP4_UI32 entry_count = 0; + stream.ReadUI32(entry_count); + m_Entries.SetItemCount(entry_count); + for (unsigned int i=0; i<entry_count; i++) { + if (version == 1) { + stream.ReadUI64(m_Entries[i].m_Time); + stream.ReadUI64(m_Entries[i].m_MoofOffset); + } else { + AP4_UI32 time = 0; + AP4_UI32 moof_offset = 0; + stream.ReadUI32(time); + stream.ReadUI32(moof_offset); + m_Entries[i].m_Time = time; + m_Entries[i].m_MoofOffset = moof_offset; + } + switch (m_LengthSizeOfTrafNumber) { + case 0: { + AP4_UI08 traf_number; + stream.ReadUI08(traf_number); + m_Entries[i].m_TrafNumber = traf_number; + break; + } + case 1: { + AP4_UI16 traf_number; + stream.ReadUI16(traf_number); + m_Entries[i].m_TrafNumber = traf_number; + break; + } + case 2: { + AP4_UI32 traf_number; + stream.ReadUI24(traf_number); + m_Entries[i].m_TrafNumber = traf_number; + break; + } + case 3: { + AP4_UI32 traf_number; + stream.ReadUI32(traf_number); + m_Entries[i].m_TrafNumber = traf_number; + break; + } + } + + switch (m_LengthSizeOfTrunNumber) { + case 0: { + AP4_UI08 trun_number; + stream.ReadUI08(trun_number); + m_Entries[i].m_TrunNumber = trun_number; + break; + } + case 1: { + AP4_UI16 trun_number; + stream.ReadUI16(trun_number); + m_Entries[i].m_TrunNumber = trun_number; + break; + } + case 2: { + AP4_UI32 trun_number; + stream.ReadUI24(trun_number); + m_Entries[i].m_TrunNumber = trun_number; + break; + } + case 3: { + AP4_UI32 trun_number; + stream.ReadUI32(trun_number); + m_Entries[i].m_TrunNumber = trun_number; + break; + } + } + + switch (m_LengthSizeOfSampleNumber) { + case 0: { + AP4_UI08 sample_number; + stream.ReadUI08(sample_number); + m_Entries[i].m_SampleNumber = sample_number; + break; + } + case 1: { + AP4_UI16 sample_number; + stream.ReadUI16(sample_number); + m_Entries[i].m_SampleNumber = sample_number; + break; + } + case 2: { + AP4_UI32 sample_number; + stream.ReadUI24(sample_number); + m_Entries[i].m_SampleNumber = sample_number; + break; + } + case 3: { + AP4_UI32 sample_number; + stream.ReadUI32(sample_number); + m_Entries[i].m_SampleNumber = sample_number; + break; + } + } + } +} + +/*---------------------------------------------------------------------- +| AP4_TfraAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TfraAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + result = stream.WriteUI32(m_TrackId); + if (AP4_FAILED(result)) return result; + AP4_UI32 fields = (m_LengthSizeOfTrafNumber<<4)| + (m_LengthSizeOfTrunNumber<<2)| + (m_LengthSizeOfSampleNumber ); + result = stream.WriteUI32(fields); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_Entries.ItemCount()); + for (unsigned int i=0; i<m_Entries.ItemCount(); i++) { + if (m_Version == 1) { + result = stream.WriteUI64(m_Entries[i].m_Time); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_Entries[i].m_MoofOffset); + if (AP4_FAILED(result)) return result; + } else { + result = stream.WriteUI32((AP4_UI32)m_Entries[i].m_Time); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_Entries[i].m_MoofOffset); + if (AP4_FAILED(result)) return result; + } + + switch (m_LengthSizeOfTrafNumber) { + case 0: + result = stream.WriteUI08((AP4_UI08)m_Entries[i].m_TrafNumber); + if (AP4_FAILED(result)) return result; + break; + + case 1: + result = stream.WriteUI16((AP4_UI16)m_Entries[i].m_TrafNumber); + if (AP4_FAILED(result)) return result; + break; + + case 2: + result = stream.WriteUI24(m_Entries[i].m_TrafNumber); + if (AP4_FAILED(result)) return result; + break; + + case 3: + result = stream.WriteUI32(m_Entries[i].m_TrafNumber); + if (AP4_FAILED(result)) return result; + break; + } + + switch (m_LengthSizeOfTrunNumber) { + case 0: + result = stream.WriteUI08((AP4_UI08)m_Entries[i].m_TrunNumber); + if (AP4_FAILED(result)) return result; + break; + + case 1: + result = stream.WriteUI16((AP4_UI16)m_Entries[i].m_TrunNumber); + if (AP4_FAILED(result)) return result; + break; + + case 2: + result = stream.WriteUI24(m_Entries[i].m_TrunNumber); + if (AP4_FAILED(result)) return result; + break; + + case 3: + result = stream.WriteUI32(m_Entries[i].m_TrunNumber); + if (AP4_FAILED(result)) return result; + break; + } + + switch (m_LengthSizeOfSampleNumber) { + case 0: + result = stream.WriteUI08((AP4_UI08)m_Entries[i].m_SampleNumber); + if (AP4_FAILED(result)) return result; + break; + + case 1: + result = stream.WriteUI16((AP4_UI16)m_Entries[i].m_SampleNumber); + if (AP4_FAILED(result)) return result; + break; + + case 2: + result = stream.WriteUI24(m_Entries[i].m_SampleNumber); + if (AP4_FAILED(result)) return result; + break; + + case 3: + result = stream.WriteUI32(m_Entries[i].m_SampleNumber); + if (AP4_FAILED(result)) return result; + break; + } + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_TfraAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TfraAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("track_ID", m_TrackId); + inspector.AddField("length_size_of_traf_num", m_LengthSizeOfTrafNumber); + inspector.AddField("length_size_of_trun_num", m_LengthSizeOfTrunNumber); + inspector.AddField("length_size_of_sample_num", m_LengthSizeOfSampleNumber); + inspector.AddField("entry count", m_Entries.ItemCount()); + if (inspector.GetVerbosity() >= 1) { + for (unsigned int i=0; i<m_Entries.ItemCount(); i++) { + char name[16]; + char value[256]; + AP4_FormatString(name, sizeof(name), "[%04d]", i); + AP4_FormatString(value, sizeof(value), + "time=%lld, moof_offset=%lld, traf_number=%d, trun_number=%d, sample_number=%d", + m_Entries[i].m_Time, + m_Entries[i].m_MoofOffset, + m_Entries[i].m_TrafNumber, + m_Entries[i].m_TrunNumber, + m_Entries[i].m_SampleNumber); + inspector.AddField(name, value); + } + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfraAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfraAtom.h new file mode 100644 index 000000000..fc5f78495 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TfraAtom.h @@ -0,0 +1,85 @@ +/***************************************************************** +| +| AP4 - tfra Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_TFRA_ATOM_H_ +#define _AP4_TFRA_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_ByteStream; + +/*---------------------------------------------------------------------- +| AP4_TfraAtom ++---------------------------------------------------------------------*/ +class AP4_TfraAtom : public AP4_Atom +{ +public: + // types + struct Entry { + Entry() : m_Time(0), m_MoofOffset(0), m_TrafNumber(0), m_TrunNumber(0), m_SampleNumber(0) {} + AP4_UI64 m_Time; + AP4_UI64 m_MoofOffset; + AP4_UI32 m_TrafNumber; + AP4_UI32 m_TrunNumber; + AP4_UI32 m_SampleNumber; + }; + + // class methods + static AP4_TfraAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // constructors + AP4_TfraAtom(); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_Array<Entry>& GetEntries() { return m_Entries; } + +private: + // methods + AP4_TfraAtom(AP4_UI32 size, AP4_UI32 version, AP4_UI32 flags, AP4_ByteStream& stream); + + // members + AP4_UI32 m_TrackId; + AP4_UI08 m_LengthSizeOfTrafNumber; + AP4_UI08 m_LengthSizeOfTrunNumber; + AP4_UI08 m_LengthSizeOfSampleNumber; + AP4_Array<Entry> m_Entries; +}; + +#endif // _AP4_TFRA_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TimsAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TimsAtom.cpp new file mode 100644 index 000000000..f6f446e7d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TimsAtom.cpp @@ -0,0 +1,75 @@ +/***************************************************************** +| +| AP4 - tims Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4TimsAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| AP4_TimsAtom::AP4_TimsAtom ++---------------------------------------------------------------------*/ +AP4_TimsAtom::AP4_TimsAtom(AP4_UI32 timescale) : + AP4_Atom(AP4_ATOM_TYPE_TIMS, AP4_ATOM_HEADER_SIZE+4), + m_TimeScale(timescale) +{ +} + +/*---------------------------------------------------------------------- +| AP4_TimsAtom::AP4_TimsAtom ++---------------------------------------------------------------------*/ +AP4_TimsAtom::AP4_TimsAtom(AP4_UI32 size, AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_TIMS, size) +{ + stream.ReadUI32(m_TimeScale); +} + +/*---------------------------------------------------------------------- +| AP4_TimsAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TimsAtom::WriteFields(AP4_ByteStream& stream) +{ + // timescale + return stream.WriteUI32(m_TimeScale); + +} + +/*---------------------------------------------------------------------- +| AP4_TimsAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TimsAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("timescale", m_TimeScale); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TimsAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TimsAtom.h new file mode 100644 index 000000000..3a78bdc2a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TimsAtom.h @@ -0,0 +1,64 @@ +/***************************************************************** +| +| AP4 - tims Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_TIMS_ATOM_H_ +#define _AP4_TIMS_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_TimsAtom ++---------------------------------------------------------------------*/ +class AP4_TimsAtom : public AP4_Atom +{ +public: + // class methods + static AP4_TimsAtom* Create(AP4_Size size, AP4_ByteStream& stream) { + return new AP4_TimsAtom(size, stream); + } + + // methods + AP4_TimsAtom(AP4_UI32 timescale); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + virtual AP4_UI32 GetTimeScale() { return m_TimeScale; } + +private: + // methods + AP4_TimsAtom(AP4_UI32 size, AP4_ByteStream& stream); + + // members + AP4_UI32 m_TimeScale; +}; + +#endif // _AP4_TIMS_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TkhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TkhdAtom.cpp new file mode 100644 index 000000000..6060ac049 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TkhdAtom.cpp @@ -0,0 +1,211 @@ +/***************************************************************** +| +| AP4 - tkhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4TkhdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TkhdAtom) + +/*---------------------------------------------------------------------- +| AP4_TkhdAtom::Create ++---------------------------------------------------------------------*/ +AP4_TkhdAtom* +AP4_TkhdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version > 1) return NULL; + return new AP4_TkhdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_TkhdAtom::AP4_TkhdAtom ++---------------------------------------------------------------------*/ +AP4_TkhdAtom::AP4_TkhdAtom(AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI32 track_id, + AP4_UI64 duration, + AP4_UI16 volume, + AP4_UI32 width, + AP4_UI32 height) : + AP4_Atom(AP4_ATOM_TYPE_TKHD, AP4_FULL_ATOM_HEADER_SIZE+80, 0, 0), + m_CreationTime(creation_time), + m_ModificationTime(modification_time), + m_TrackId(track_id), + m_Reserved1(0), + m_Duration(duration), + m_Layer(0), + m_AlternateGroup(0), + m_Volume(volume), + m_Reserved3(0), + m_Width(width), + m_Height(height) +{ + m_Flags = AP4_TKHD_FLAG_DEFAULTS; + + m_Matrix[0] = 0x00010000; + m_Matrix[1] = 0; + m_Matrix[2] = 0; + m_Matrix[3] = 0; + m_Matrix[4] = 0x00010000; + m_Matrix[5] = 0; + m_Matrix[6] = 0; + m_Matrix[7] = 0; + m_Matrix[8] = 0x40000000; + + m_Reserved2[0] = 0; + m_Reserved2[1] = 0; +} + +/*---------------------------------------------------------------------- +| AP4_TkhdAtom::AP4_TkhdAtom ++---------------------------------------------------------------------*/ +AP4_TkhdAtom::AP4_TkhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_TKHD, size, version, flags) +{ + if (m_Version == 0) { + // we only deal with version 0 for now + AP4_UI32 creation_time; + stream.ReadUI32(creation_time); + m_CreationTime = creation_time; + AP4_UI32 modification_time; + stream.ReadUI32(modification_time); + m_ModificationTime = modification_time; + stream.ReadUI32(m_TrackId); + stream.ReadUI32(m_Reserved1); + AP4_UI32 duration; + stream.ReadUI32(duration); + m_Duration = duration; + } else { + stream.ReadUI64(m_CreationTime); + stream.ReadUI64(m_ModificationTime); + stream.ReadUI32(m_TrackId); + stream.ReadUI32(m_Reserved1); + stream.ReadUI64(m_Duration); + } + + stream.Read((void*)m_Reserved2, 8); + stream.ReadUI16(m_Layer); + stream.ReadUI16(m_AlternateGroup); + stream.ReadUI16(m_Volume); + stream.ReadUI16(m_Reserved3); + for (int i=0; i<9; i++) { + stream.ReadUI32(m_Matrix[i]); + } + stream.ReadUI32(m_Width); + stream.ReadUI32(m_Height); +} + +/*---------------------------------------------------------------------- +| AP4_TkhdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TkhdAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // creation/modification time, track id, reserved1 & duration + if (m_Version == 0) { + result = stream.WriteUI32((AP4_UI32)m_CreationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_ModificationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_TrackId); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_Reserved1); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32((AP4_UI32)m_Duration); + if (AP4_FAILED(result)) return result; + } else { + result = stream.WriteUI64(m_CreationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_ModificationTime); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_TrackId); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_Reserved1); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI64(m_Duration); + if (AP4_FAILED(result)) return result; + } + + // reserved2 + result = stream.Write(m_Reserved2, sizeof(m_Reserved2)); + if (AP4_FAILED(result)) return result; + + // layer, alternate group & volume + result = stream.WriteUI16(m_Layer); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI16(m_AlternateGroup); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI16(m_Volume); + if (AP4_FAILED(result)) return result; + + // reserved3 + result = stream.WriteUI16(m_Reserved3); + + // matrix + for (int i=0; i<9; i++) { + result = stream.WriteUI32(m_Matrix[i]); + if (AP4_FAILED(result)) return result; + } + + // width & height + result = stream.WriteUI32(m_Width); + if (AP4_FAILED(result)) return result; + result = stream.WriteUI32(m_Height); + if (AP4_FAILED(result)) return result; + + return result; +} + +/*---------------------------------------------------------------------- +| AP4_TkhdAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TkhdAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("enabled", ((m_Flags & AP4_TKHD_FLAG_TRACK_ENABLED) ? 1 : 0), AP4_AtomInspector::HINT_BOOLEAN); + inspector.AddField("id", m_TrackId); + inspector.AddField("duration", m_Duration); + inspector.AddFieldF("width", (float)m_Width/65536.0f); + inspector.AddFieldF("height", (float)m_Height/65536.0f); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TkhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TkhdAtom.h new file mode 100644 index 000000000..d0d0f7b68 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TkhdAtom.h @@ -0,0 +1,106 @@ +/***************************************************************** +| +| AP4 - tkhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_TKHD_ATOM_H_ +#define _AP4_TKHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int AP4_TKHD_FLAG_TRACK_ENABLED = 1; +const int AP4_TKHD_FLAG_TRACK_IN_MOVIE = 2; +const int AP4_TKHD_FLAG_TRACK_IN_PREVIEW = 4; + +const int AP4_TKHD_FLAG_DEFAULTS = 7; + +/*---------------------------------------------------------------------- +| AP4_TkhdAtom ++---------------------------------------------------------------------*/ +class AP4_TkhdAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_TkhdAtom, AP4_Atom) + + // class methods + static AP4_TkhdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_TkhdAtom(AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI32 track_id, + AP4_UI64 duration, + AP4_UI16 volume, + AP4_UI32 width, + AP4_UI32 height); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + AP4_UI64 GetDuration() { return m_Duration; } + void SetDuration(AP4_UI64 duration) { m_Duration = duration; } + AP4_UI32 GetTrackId() { return m_TrackId; } + void SetTrackId(AP4_UI32 track_id) { m_TrackId = track_id; } + + void GetTranslation(float& x, float& y) { + x = (float)(*(int*)&m_Matrix[6]) / 65536; + y = (float)(*(int*)&m_Matrix[7]) / 65536; + } + + AP4_UI32 GetWidth() { return m_Width; } + void SetWidth(AP4_UI32 width) { m_Width = width; } + AP4_UI32 GetHeight() { return m_Height; } + void SetHeight(AP4_UI32 height) { m_Height = height; } + + private: + // methods + AP4_TkhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI64 m_CreationTime; + AP4_UI64 m_ModificationTime; + AP4_UI32 m_TrackId; + AP4_UI32 m_Reserved1; + AP4_UI64 m_Duration; + AP4_UI32 m_Reserved2[2]; + AP4_UI16 m_Layer; + AP4_UI16 m_AlternateGroup; + AP4_UI16 m_Volume; + AP4_UI16 m_Reserved3; + AP4_UI32 m_Matrix[9]; + AP4_UI32 m_Width; + AP4_UI32 m_Height; +}; + +#endif // _AP4_TKHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Track.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Track.cpp new file mode 100644 index 000000000..9dc915571 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Track.cpp @@ -0,0 +1,471 @@ +/***************************************************************** +| +| AP4 - Track Objects +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4ByteStream.h" +#include "Ap4HdlrAtom.h" +#include "Ap4MvhdAtom.h" +#include "Ap4Track.h" +#include "Ap4Utils.h" +#include "Ap4Sample.h" +#include "Ap4DataBuffer.h" +#include "Ap4TrakAtom.h" +#include "Ap4TkhdAtom.h" +#include "Ap4MoovAtom.h" +#include "Ap4AtomSampleTable.h" +#include "Ap4SdpAtom.h" +#include "Ap4MdhdAtom.h" +#include "Ap4SyntheticSampleTable.h" + +/*---------------------------------------------------------------------- +| AP4_Track::AP4_Track ++---------------------------------------------------------------------*/ +AP4_Track::AP4_Track(Type type, + AP4_SampleTable* sample_table, + AP4_UI32 track_id, + AP4_UI32 movie_time_scale, + AP4_UI64 track_duration, + AP4_UI32 media_time_scale, + AP4_UI64 media_duration, + const char* language, + AP4_UI32 width, + AP4_UI32 height) : + m_TrakAtomIsOwned(true), + m_Type(type), + m_SampleTable(sample_table), + m_SampleTableIsOwned(true), + m_MovieTimeScale(movie_time_scale ? + movie_time_scale : + AP4_TRACK_DEFAULT_MOVIE_TIMESCALE) +{ + // compute the default volume value + unsigned int volume = 0; + if (type == TYPE_AUDIO) volume = 0x100; + + // compute the handler type and name + AP4_Atom::Type hdlr_type; + const char* hdlr_name; + switch (type) { + case TYPE_AUDIO: + hdlr_type = AP4_HANDLER_TYPE_SOUN; + hdlr_name = "Bento4 Sound Handler"; + break; + + case TYPE_VIDEO: + hdlr_type = AP4_HANDLER_TYPE_VIDE; + hdlr_name = "Bento4 Video Handler"; + break; + + case TYPE_HINT: + hdlr_type = AP4_HANDLER_TYPE_HINT; + hdlr_name = "Bento4 Hint Handler"; + break; + + case TYPE_TEXT: + hdlr_type = AP4_HANDLER_TYPE_TEXT; + hdlr_name = "Bento4 Text Handler"; + break; + + default: + hdlr_type = 0; + hdlr_name = NULL; + break; + } + + // create a trak atom + m_TrakAtom = new AP4_TrakAtom(sample_table, + hdlr_type, + hdlr_name, + track_id, + 0, + 0, + track_duration, + media_time_scale, + media_duration, + volume, + language, + width, + height); +} + +/*---------------------------------------------------------------------- +| AP4_Track::AP4_Track ++---------------------------------------------------------------------*/ +AP4_Track::AP4_Track(AP4_TrakAtom& atom, + AP4_ByteStream& sample_stream, + AP4_UI32 movie_time_scale) : + m_TrakAtom(&atom), + m_TrakAtomIsOwned(false), + m_Type(TYPE_UNKNOWN), + m_SampleTable(NULL), + m_SampleTableIsOwned(true), + m_MovieTimeScale(movie_time_scale) +{ + // find the handler type + AP4_Atom* sub = atom.FindChild("mdia/hdlr"); + if (sub) { + AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, sub); + if (hdlr) { + AP4_UI32 type = hdlr->GetHandlerType(); + if (type == AP4_HANDLER_TYPE_SOUN) { + m_Type = TYPE_AUDIO; + } else if (type == AP4_HANDLER_TYPE_VIDE) { + m_Type = TYPE_VIDEO; + } else if (type == AP4_HANDLER_TYPE_HINT) { + m_Type = TYPE_HINT; + } else if (type == AP4_HANDLER_TYPE_ODSM || + type == AP4_HANDLER_TYPE_SDSM) { + m_Type = TYPE_SYSTEM; + } else if (type == AP4_HANDLER_TYPE_TEXT || + type == AP4_HANDLER_TYPE_TX3G) { + m_Type = TYPE_TEXT; + } else if (type == AP4_HANDLER_TYPE_JPEG) { + m_Type = TYPE_JPEG; + // ==> Start patch MPC + } else if (type == AP4_HANDLER_TYPE_SUBP) { + m_Type = TYPE_SUBP; + // <== End patch MPC + } + } + } + + // create a facade for the stbl atom + AP4_ContainerAtom* stbl = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom.FindChild("mdia/minf/stbl")); + if (stbl) { + m_SampleTable = new AP4_AtomSampleTable(stbl, sample_stream); + } +} + +/*---------------------------------------------------------------------- +| AP4_Track::~AP4_Track ++---------------------------------------------------------------------*/ +AP4_Track::~AP4_Track() +{ + if (m_TrakAtomIsOwned) delete m_TrakAtom; + if (m_SampleTableIsOwned) delete m_SampleTable; +} + +/*---------------------------------------------------------------------- +| AP4_Track::Clone ++---------------------------------------------------------------------*/ +AP4_Track* +AP4_Track::Clone(AP4_Result* result) +{ + AP4_SyntheticSampleTable* sample_table = new AP4_SyntheticSampleTable(); + + // default return value + if (result) *result = AP4_SUCCESS; + + // add clones of the sample descriptions to the new sample table + for (unsigned int i=0; ;i++) { + AP4_SampleDescription* sample_description = GetSampleDescription(i); + if (sample_description == NULL) break; + sample_table->AddSampleDescription(sample_description->Clone()); + } + + AP4_Sample sample; + AP4_Ordinal index = 0; + while (AP4_SUCCEEDED(GetSample(index, sample))) { + AP4_ByteStream* data_stream; + data_stream = sample.GetDataStream(); + sample_table->AddSample(*data_stream, + sample.GetOffset(), + sample.GetSize(), + sample.GetDuration(), + sample.GetDescriptionIndex(), + sample.GetDts(), + sample.GetCtsDelta(), + sample.IsSync()); + AP4_RELEASE(data_stream); // release our ref, the table has kept its own ref. + index++; + } + + // create the cloned track + AP4_Track* clone = new AP4_Track(GetType(), + sample_table, + GetId(), + GetMovieTimeScale(), + GetDuration(), + GetMediaTimeScale(), + GetMediaDuration(), + GetTrackLanguage().GetChars(), + GetWidth(), + GetHeight()); + + return clone; +} + +/*---------------------------------------------------------------------- +| AP4_Track::Attach ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::Attach(AP4_MoovAtom* moov) +{ + if (!m_TrakAtomIsOwned) return AP4_ERROR_INTERNAL; + moov->AddChild(m_TrakAtom); + m_TrakAtomIsOwned = false; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetFlags ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_Track::GetFlags() +{ + if (m_TrakAtom) { + AP4_TkhdAtom* tkhd = AP4_DYNAMIC_CAST(AP4_TkhdAtom, m_TrakAtom->FindChild("tkhd")); + if (tkhd) { + return tkhd->GetFlags(); + } + } + return 0; +} + +/*---------------------------------------------------------------------- +| AP4_Track::SetFlags ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::SetFlags(AP4_UI32 flags) +{ + if (m_TrakAtom) { + AP4_TkhdAtom* tkhd = AP4_DYNAMIC_CAST(AP4_TkhdAtom, m_TrakAtom->FindChild("tkhd")); + if (tkhd) { + tkhd->SetFlags(flags); + return AP4_SUCCESS; + } + } + return AP4_ERROR_INVALID_STATE; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetHandlerType ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_Track::GetHandlerType() +{ + if (m_TrakAtom) { + AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, m_TrakAtom->FindChild("mdia/hdlr")); + if (hdlr) { + return hdlr->GetHandlerType(); + } + } + return 0; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetId ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_Track::GetId() +{ + return m_TrakAtom->GetId(); +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetWidth ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_Track::GetWidth() +{ + return m_TrakAtom->GetWidth(); +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetHeight ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_Track::GetHeight() +{ + return m_TrakAtom->GetHeight(); +} + +/*---------------------------------------------------------------------- +| AP4_Track::SetId ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::SetId(AP4_UI32 id) +{ + m_TrakAtom->SetId(id); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetDuration ++---------------------------------------------------------------------*/ +AP4_UI64 +AP4_Track::GetDuration() +{ + return m_TrakAtom->GetDuration(); +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetDurationMs ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_Track::GetDurationMs() +{ + AP4_UI64 duration = m_TrakAtom->GetDuration(); + return AP4_DurationMsFromUnits(duration, m_MovieTimeScale); +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetSampleCount ++---------------------------------------------------------------------*/ +AP4_Cardinal +AP4_Track::GetSampleCount() +{ + // delegate to the sample table + return m_SampleTable ? m_SampleTable->GetSampleCount() : 0; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::GetSample(AP4_Ordinal index, AP4_Sample& sample) +{ + // delegate to the sample table + return m_SampleTable ? m_SampleTable->GetSample(index, sample) : AP4_FAILURE; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetSampleDescription ++---------------------------------------------------------------------*/ +AP4_SampleDescription* +AP4_Track::GetSampleDescription(AP4_Ordinal index) +{ + // delegate to the sample table + return m_SampleTable ? m_SampleTable->GetSampleDescription(index) : NULL; +} + +/*---------------------------------------------------------------------- +| AP4_Track::ReadSample ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::ReadSample(AP4_Ordinal index, + AP4_Sample& sample, + AP4_DataBuffer& data) +{ + AP4_Result result; + + // get the sample + result = GetSample(index, sample); + if (AP4_FAILED(result)) return result; + + // read the data + return sample.ReadData(data); +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetSampleIndexForTimeStampMs ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::GetSampleIndexForTimeStampMs(AP4_UI32 ts_ms, AP4_Ordinal& index) +{ + // convert the ts in the timescale of the track's media + AP4_UI64 ts = AP4_ConvertTime(ts_ms, 1000, GetMediaTimeScale()); + + return m_SampleTable->GetSampleIndexForTimeStamp(ts, index); +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetNearestSyncSampleIndex ++---------------------------------------------------------------------*/ +AP4_Ordinal +AP4_Track::GetNearestSyncSampleIndex(AP4_Ordinal index, bool before /* = true */) +{ + if (m_SampleTable == NULL) return index; + return m_SampleTable->GetNearestSyncSampleIndex(index, before); +} + +/*---------------------------------------------------------------------- +| AP4_Track::SetMovieTimeScale ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Track::SetMovieTimeScale(AP4_UI32 time_scale) +{ + // check that we can convert + if (m_MovieTimeScale == 0) return AP4_FAILURE; + + // convert from one time scale to the other + m_TrakAtom->SetDuration(AP4_ConvertTime(m_TrakAtom->GetDuration(), + m_MovieTimeScale, + time_scale)); + + // keep the new movie timescale + m_MovieTimeScale = time_scale; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetMediaTimeScale ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_Track::GetMediaTimeScale() +{ + return m_TrakAtom?m_TrakAtom->GetMediaTimeScale():0; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetMediaDuration ++---------------------------------------------------------------------*/ +AP4_UI64 +AP4_Track::GetMediaDuration() +{ + return m_TrakAtom?m_TrakAtom->GetMediaDuration():0; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetTrackName ++---------------------------------------------------------------------*/ +const AP4_String +AP4_Track::GetTrackName() +{ + if (AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, m_TrakAtom->FindChild("mdia/hdlr"))) { + return hdlr->GetHandlerName(); + } + return NULL; +} + +/*---------------------------------------------------------------------- +| AP4_Track::GetTrackLanguage ++---------------------------------------------------------------------*/ +const AP4_String +AP4_Track::GetTrackLanguage() +{ + if (AP4_MdhdAtom* mdhd = AP4_DYNAMIC_CAST(AP4_MdhdAtom, m_TrakAtom->FindChild("mdia/mdhd"))) { + return mdhd->GetLanguage(); + } + return NULL; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Track.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Track.h new file mode 100644 index 000000000..12b48560c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Track.h @@ -0,0 +1,145 @@ +/***************************************************************** +| +| AP4 - Track Objects +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_TRAK_H_ +#define _AP4_TRAK_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Array.h" + +// ==> Start patch MPC +#include "Ap4String.h" +// <== End patch MPC + +/*---------------------------------------------------------------------- +| forward declarations ++---------------------------------------------------------------------*/ +class AP4_StblAtom; +class AP4_ByteStream; +class AP4_Sample; +class AP4_DataBuffer; +class AP4_TrakAtom; +class AP4_MoovAtom; +class AP4_SampleDescription; +class AP4_SampleTable; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const AP4_UI32 AP4_TRACK_DEFAULT_MOVIE_TIMESCALE = 1000; + +const AP4_UI32 AP4_TRACK_FLAG_ENABLED = 0x0001; +const AP4_UI32 AP4_TRACK_FLAG_IN_MOVIE = 0x0002; +const AP4_UI32 AP4_TRACK_FLAG_IN_PREVIEW = 0x0004; + +/*---------------------------------------------------------------------- +| AP4_Track ++---------------------------------------------------------------------*/ +class AP4_Track { + public: + // types + typedef enum { + TYPE_UNKNOWN = 0, + TYPE_AUDIO = 1, + TYPE_VIDEO = 2, + TYPE_SYSTEM = 3, + TYPE_HINT = 4, + TYPE_TEXT = 5, + TYPE_JPEG = 6, + TYPE_RTP = 7, + // ==> Start patch MPC + TYPE_SUBP = 8 + // <== End patch MPC + } Type; + + // methods + AP4_Track(Type type, + AP4_SampleTable* sample_table, // ownership is transfered to the AP4_Track object + AP4_UI32 track_id, + AP4_UI32 movie_time_scale, // 0 = use default + AP4_UI64 track_duration, // in the movie timescale + AP4_UI32 media_time_scale, + AP4_UI64 media_duration, // in the media timescale + const char* language, + AP4_UI32 width, // in 16.16 fixed point + AP4_UI32 height); // in 16.16 fixed point + AP4_Track(AP4_TrakAtom& atom, + AP4_ByteStream& sample_stream, + AP4_UI32 movie_time_scale); + virtual ~AP4_Track(); + + /** + * Clone a track. This is useful if you want to create a track from + * a non-synthetic track (parsed from a file for example) and + * write it out + */ + AP4_Track* Clone(AP4_Result* result = NULL); + + AP4_UI32 GetFlags(); + AP4_Result SetFlags(AP4_UI32 flags); + AP4_Track::Type GetType() { return m_Type; } + AP4_UI32 GetHandlerType(); + AP4_UI64 GetDuration(); // in the timescale of the movie + AP4_UI32 GetDurationMs(); // in milliseconds + AP4_UI32 GetWidth(); // in 16.16 fixed point + AP4_UI32 GetHeight(); // in 16.16 fixed point + AP4_Cardinal GetSampleCount(); + AP4_Result GetSample(AP4_Ordinal index, AP4_Sample& sample); + AP4_Result ReadSample(AP4_Ordinal index, + AP4_Sample& sample, + AP4_DataBuffer& data); + AP4_Result GetSampleIndexForTimeStampMs(AP4_UI32 ts_ms, + AP4_Ordinal& index); + AP4_Ordinal GetNearestSyncSampleIndex(AP4_Ordinal index, bool before=true); + AP4_SampleDescription* GetSampleDescription(AP4_Ordinal index); + AP4_SampleTable* GetSampleTable() { return m_SampleTable; } + AP4_UI32 GetId(); + AP4_Result SetId(AP4_UI32 track_id); + AP4_TrakAtom* GetTrakAtom() { return m_TrakAtom; } + AP4_Result SetMovieTimeScale(AP4_UI32 time_scale); + AP4_UI32 GetMovieTimeScale() { return m_MovieTimeScale; } + AP4_UI32 GetMediaTimeScale(); + AP4_UI64 GetMediaDuration(); // in the timescale of the media + const AP4_String GetTrackName(); + const AP4_String GetTrackLanguage(); + AP4_Result Attach(AP4_MoovAtom* moov); + + protected: + // members + AP4_TrakAtom* m_TrakAtom; + bool m_TrakAtomIsOwned; + Type m_Type; + AP4_SampleTable* m_SampleTable; + bool m_SampleTableIsOwned; + AP4_UI32 m_MovieTimeScale; +}; + +#endif // _AP4_TRAK_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrakAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrakAtom.cpp new file mode 100644 index 000000000..57202f92e --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrakAtom.cpp @@ -0,0 +1,382 @@ +/***************************************************************** +| +| AP4 - trak Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4TrakAtom.h" +#include "Ap4MdhdAtom.h" +#include "Ap4TkhdAtom.h" +#include "Ap4HdlrAtom.h" +#include "Ap4VmhdAtom.h" +#include "Ap4SmhdAtom.h" +#include "Ap4HmhdAtom.h" +#include "Ap4NmhdAtom.h" +#include "Ap4DrefAtom.h" +#include "Ap4UrlAtom.h" +#include "Ap4StcoAtom.h" +#include "Ap4Co64Atom.h" +#include "Ap4AtomFactory.h" +#include "Ap4SampleTable.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TrakAtom) + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::AP4_TrakAtom ++---------------------------------------------------------------------*/ +AP4_TrakAtom::AP4_TrakAtom(AP4_SampleTable* sample_table, + AP4_Atom::Type hdlr_type, + const char* hdlr_name, + AP4_UI32 track_id, + AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI64 track_duration, + AP4_UI32 media_time_scale, + AP4_UI64 media_duration, + AP4_UI16 volume, + const char* language, + AP4_UI32 width, + AP4_UI32 height) : + AP4_ContainerAtom(AP4_ATOM_TYPE_TRAK) +{ + AP4_Result result; + + // create a tkhd atom + m_TkhdAtom = new AP4_TkhdAtom(creation_time, + modification_time, + track_id, + track_duration, + volume, + width, + height); + + // create an edts + + // create a mdia atom + AP4_ContainerAtom* mdia = new AP4_ContainerAtom(AP4_ATOM_TYPE_MDIA); + + // create a hdlr atom for the mdia atom + AP4_HdlrAtom* hdlr = new AP4_HdlrAtom(hdlr_type, hdlr_name); + + // create a minf atom + AP4_ContainerAtom* minf = new AP4_ContainerAtom(AP4_ATOM_TYPE_MINF); + + // create a media header atom for minf (vmhd, smhd, hmhd or nmhd) + AP4_Atom* minf_header; + switch (hdlr_type) { + case AP4_HANDLER_TYPE_VIDE: + minf_header = new AP4_VmhdAtom(0, 0, 0, 0); + break; + + case AP4_HANDLER_TYPE_SOUN: + minf_header = new AP4_SmhdAtom(0); + break; + + default: + minf_header = new AP4_NmhdAtom(); + break; + } + + // create a dinf atom for minf + AP4_ContainerAtom* dinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_DINF); + + // create a url atom as a ref for dref + AP4_Atom* url = new AP4_UrlAtom(); // local ref + + // create a dref atom for dinf + AP4_DrefAtom* dref = new AP4_DrefAtom(&url, 1); + + // create a stbl atom for minf + AP4_ContainerAtom* stbl; + result = sample_table->GenerateStblAtom(stbl); + if (AP4_FAILED(result)) stbl = NULL; + + // populate the dinf atom + dinf->AddChild(dref); + + // populate the minf atom + minf->AddChild(minf_header); + minf->AddChild(dinf); + if (stbl) minf->AddChild(stbl); + + // create a mdhd atom for the mdia atom + m_MdhdAtom = new AP4_MdhdAtom(creation_time, + modification_time, + media_time_scale, + media_duration, + language); + + // populate the mdia atom + mdia->AddChild(m_MdhdAtom); + mdia->AddChild(hdlr); + mdia->AddChild(minf); + + // attach the children + AddChild(m_TkhdAtom); + AddChild(mdia); +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::AP4_TrakAtom ++---------------------------------------------------------------------*/ +AP4_TrakAtom::AP4_TrakAtom(AP4_UI32 size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_ContainerAtom(AP4_ATOM_TYPE_TRAK, size, false, stream, atom_factory) +{ + m_TkhdAtom = AP4_DYNAMIC_CAST(AP4_TkhdAtom, FindChild("tkhd")); + m_MdhdAtom = AP4_DYNAMIC_CAST(AP4_MdhdAtom, FindChild("mdia/mdhd")); +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::GetId ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_TrakAtom::GetId() +{ + return m_TkhdAtom?m_TkhdAtom->GetTrackId():0; +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::SetId ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::SetId(AP4_UI32 id) +{ + if (m_TkhdAtom) { + m_TkhdAtom->SetTrackId(id); + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::GetMediaTimeScale ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_TrakAtom::GetMediaTimeScale() +{ + return m_MdhdAtom?m_MdhdAtom->GetTimeScale():0; +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::SetMediaTimeScale ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::SetMediaTimeScale(AP4_UI32 timescale) +{ + if (m_MdhdAtom) { + m_MdhdAtom->SetTimeScale(timescale); + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::GetDuration ++---------------------------------------------------------------------*/ +AP4_UI64 +AP4_TrakAtom::GetDuration() +{ + return m_TkhdAtom?m_TkhdAtom->GetDuration():0; +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::SetDuration ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::SetDuration(AP4_UI64 duration) +{ + if (m_TkhdAtom) { + m_TkhdAtom->SetDuration(duration); + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::GetMediaDuration ++---------------------------------------------------------------------*/ +AP4_UI64 +AP4_TrakAtom::GetMediaDuration() +{ + return m_MdhdAtom?m_MdhdAtom->GetDuration():0; +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::SetMediaDuration ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::SetMediaDuration(AP4_UI32 duration) +{ + if (m_MdhdAtom) { + m_MdhdAtom->SetDuration(duration); + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::GetWidth ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_TrakAtom::GetWidth() +{ + return m_TkhdAtom?m_TkhdAtom->GetWidth():0; +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::SetWidth ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::SetWidth(AP4_UI32 width) +{ + if (m_TkhdAtom) { + m_TkhdAtom->SetWidth(width); + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::GetHeight ++---------------------------------------------------------------------*/ +AP4_UI32 +AP4_TrakAtom::GetHeight() +{ + return m_TkhdAtom?m_TkhdAtom->GetHeight():0; +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::SetHeight ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::SetHeight(AP4_UI32 height) +{ + if (m_TkhdAtom) { + m_TkhdAtom->SetHeight(height); + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::AdjustChunkOffsets ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::AdjustChunkOffsets(AP4_SI64 delta) +{ + AP4_Atom* atom; + if ((atom = FindChild("mdia/minf/stbl/stco"))) { + AP4_StcoAtom* stco = AP4_DYNAMIC_CAST(AP4_StcoAtom, atom); + return stco->AdjustChunkOffsets((int)delta); + } else if ((atom = FindChild("mdia/minf/stbl/co64"))) { + AP4_Co64Atom* co64 = AP4_DYNAMIC_CAST(AP4_Co64Atom, atom); + return co64->AdjustChunkOffsets(delta); + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::GetChunkOffsets ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::GetChunkOffsets(AP4_Array<AP4_UI64>& chunk_offsets) +{ + AP4_Atom* atom; + if ((atom = FindChild("mdia/minf/stbl/stco"))) { + AP4_StcoAtom* stco = AP4_DYNAMIC_CAST(AP4_StcoAtom, atom); + if (stco == NULL) return AP4_ERROR_INTERNAL; + AP4_Cardinal stco_chunk_count = stco->GetChunkCount(); + const AP4_UI32* stco_chunk_offsets = stco->GetChunkOffsets(); + chunk_offsets.SetItemCount(stco_chunk_count); + for (unsigned int i=0; i<stco_chunk_count; i++) { + chunk_offsets[i] = stco_chunk_offsets[i]; + } + return AP4_SUCCESS; + } else if ((atom = FindChild("mdia/minf/stbl/co64"))) { + AP4_Co64Atom* co64 = AP4_DYNAMIC_CAST(AP4_Co64Atom, atom); + if (co64 == NULL) return AP4_ERROR_INTERNAL; + AP4_Cardinal co64_chunk_count = co64->GetChunkCount(); + const AP4_UI64* co64_chunk_offsets = co64->GetChunkOffsets(); + chunk_offsets.SetItemCount(co64_chunk_count); + for (unsigned int i=0; i<co64_chunk_count; i++) { + chunk_offsets[i] = co64_chunk_offsets[i]; + } + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrakAtom::SetChunkOffsets ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrakAtom::SetChunkOffsets(const AP4_Array<AP4_UI64>& chunk_offsets) +{ + AP4_Atom* atom; + if ((atom = FindChild("mdia/minf/stbl/stco"))) { + AP4_StcoAtom* stco = AP4_DYNAMIC_CAST(AP4_StcoAtom, atom); + if (stco == NULL) return AP4_ERROR_INTERNAL; + AP4_Cardinal stco_chunk_count = stco->GetChunkCount(); + AP4_UI32* stco_chunk_offsets = stco->GetChunkOffsets(); + if (stco_chunk_count > chunk_offsets.ItemCount()) { + return AP4_ERROR_OUT_OF_RANGE; + } + for (unsigned int i=0; i<stco_chunk_count; i++) { + stco_chunk_offsets[i] = (AP4_UI32)chunk_offsets[i]; + } + return AP4_SUCCESS; + } else if ((atom = FindChild("mdia/minf/stbl/co64"))) { + AP4_Co64Atom* co64 = AP4_DYNAMIC_CAST(AP4_Co64Atom, atom); + if (co64 == NULL) return AP4_ERROR_INTERNAL; + AP4_Cardinal co64_chunk_count = co64->GetChunkCount(); + AP4_UI64* co64_chunk_offsets = co64->GetChunkOffsets(); + if (co64_chunk_count > chunk_offsets.ItemCount()) { + return AP4_ERROR_OUT_OF_RANGE; + } + for (unsigned int i=0; i<co64_chunk_count; i++) { + co64_chunk_offsets[i] = chunk_offsets[i]; + } + return AP4_SUCCESS; + } else { + return AP4_ERROR_INVALID_STATE; + } +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrakAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrakAtom.h new file mode 100644 index 000000000..8006375ee --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrakAtom.h @@ -0,0 +1,103 @@ +/***************************************************************** +| +| AP4 - trak Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_TRAK_ATOM_H_ +#define _AP4_TRAK_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4ContainerAtom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_HdlrAtom; +class AP4_TkhdAtom; +class AP4_MdhdAtom; +class AP4_SampleTable; + +/*---------------------------------------------------------------------- +| AP4_TrakAtom ++---------------------------------------------------------------------*/ +class AP4_TrakAtom : public AP4_ContainerAtom +{ + public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_TrakAtom, AP4_ContainerAtom) + + // class methods + static AP4_TrakAtom* Create(AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) { + return new AP4_TrakAtom(size, stream, atom_factory); + } + + // methods + AP4_TrakAtom(AP4_SampleTable* sample_table, + AP4_Atom::Type hdlr_type, + const char* hdlr_name, + AP4_UI32 track_id, + AP4_UI32 creation_time, + AP4_UI32 modification_time, + AP4_UI64 track_duration, + AP4_UI32 media_time_scale, + AP4_UI64 media_duration, + AP4_UI16 volume, + const char* language, + AP4_UI32 width, + AP4_UI32 heigh); + AP4_TkhdAtom* GetTkhdAtom() { return m_TkhdAtom; } + AP4_Result AdjustChunkOffsets(AP4_SI64 delta); + AP4_Result GetChunkOffsets(AP4_Array<AP4_UI64>& chunk_offsets); + AP4_Result SetChunkOffsets(const AP4_Array<AP4_UI64>& chunk_offsets); + AP4_UI32 GetId(); + AP4_Result SetId(AP4_UI32 track_id); + AP4_UI64 GetDuration(); + AP4_Result SetDuration(AP4_UI64 duration); + AP4_UI64 GetMediaDuration(); + AP4_Result SetMediaDuration(AP4_UI32 duration); + AP4_UI32 GetMediaTimeScale(); + AP4_Result SetMediaTimeScale(AP4_UI32 timescale); + AP4_UI32 GetWidth(); + AP4_Result SetWidth(AP4_UI32 width); + AP4_UI32 GetHeight(); + AP4_Result SetHeight(AP4_UI32 height); + + private: + // methods + AP4_TrakAtom(AP4_UI32 size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); + + // members + AP4_TkhdAtom* m_TkhdAtom; + AP4_MdhdAtom* m_MdhdAtom; +}; + +#endif // _AP4_TRAK_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrefTypeAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrefTypeAtom.cpp new file mode 100644 index 000000000..bac78fd4c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrefTypeAtom.cpp @@ -0,0 +1,107 @@ +/***************************************************************** +| +| AP4 - tref type Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4TrefTypeAtom.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TrefTypeAtom) + +/*---------------------------------------------------------------------- +| AP4_TrefTypeAtom::AP4_TrefTypeAtom ++---------------------------------------------------------------------*/ +AP4_TrefTypeAtom::AP4_TrefTypeAtom(AP4_Atom::Type type) : + AP4_Atom(type, AP4_ATOM_HEADER_SIZE) +{ +} + +/*---------------------------------------------------------------------- +| AP4_TrefTypeAtom::AP4_TrefTypeAtom ++---------------------------------------------------------------------*/ +AP4_TrefTypeAtom::AP4_TrefTypeAtom(AP4_Atom::Type type, + AP4_UI32 size, + AP4_ByteStream& stream) : + AP4_Atom(type, size) +{ + AP4_Size data_size = size - 8; // size and atom type + + // read the track ids + while (data_size >= 4) { + AP4_UI32 track_id; + stream.ReadUI32(track_id); + m_TrackIds.Append(track_id); + data_size -= 4; + } +} + +/*---------------------------------------------------------------------- +| AP4_TrefTypeAtom::AddTrackId ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrefTypeAtom::AddTrackId(AP4_UI32 track_id) +{ + AP4_Result result = m_TrackIds.Append(track_id); + if (AP4_SUCCEEDED(result)) { + m_Size32 += 4; + } + return result; +} + +/*---------------------------------------------------------------------- +| AP4_TrefTypeAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrefTypeAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result = AP4_SUCCESS; + + AP4_Size track_id_count = m_TrackIds.ItemCount(); + for (AP4_Ordinal i=0; i<track_id_count; i++) { + result = stream.WriteUI32(m_TrackIds[i]); + if (AP4_FAILED(result)) return result; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_TrefTypeAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrefTypeAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("track_id_count", m_TrackIds.ItemCount()); + for (AP4_Ordinal i=0; i<m_TrackIds.ItemCount(); i++) { + inspector.AddField("track id ", m_TrackIds[i]); + } + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrefTypeAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrefTypeAtom.h new file mode 100644 index 000000000..438f03f53 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrefTypeAtom.h @@ -0,0 +1,73 @@ +/***************************************************************** +| +| AP4 - tref type Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_TREF_TYPE_ATOM_H_ +#define _AP4_TREF_TYPE_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4Array.h" + +/*---------------------------------------------------------------------- +| AP4_TrefTypeAtom ++---------------------------------------------------------------------*/ +class AP4_TrefTypeAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_TrefTypeAtom, AP4_Atom) + + // class methods + static AP4_TrefTypeAtom* Create(AP4_Atom::Type type, + AP4_UI32 size, + AP4_ByteStream& stream) { + return new AP4_TrefTypeAtom(type, size, stream); + } + + // contructor + AP4_TrefTypeAtom(AP4_Atom::Type type); + + // methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + AP4_Result AddTrackId(AP4_UI32 track_id); + + // accessors + const AP4_Array<AP4_UI32>& GetTrackIds() { return m_TrackIds; } + +private: + // methods + AP4_TrefTypeAtom(AP4_Atom::Type type, AP4_UI32 size, AP4_ByteStream& stream); + + // members + AP4_Array<AP4_UI32> m_TrackIds; +}; + +#endif + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrexAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrexAtom.cpp new file mode 100644 index 000000000..6745e764a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrexAtom.cpp @@ -0,0 +1,115 @@ +/***************************************************************** +| +| AP4 - trex Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4TrexAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| dynamic cast support ++---------------------------------------------------------------------*/ +AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TrexAtom) + +/*---------------------------------------------------------------------- +| AP4_TrexAtom::Create ++---------------------------------------------------------------------*/ +AP4_TrexAtom* +AP4_TrexAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_TrexAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_TrexAtom::AP4_TrexAtom ++---------------------------------------------------------------------*/ +AP4_TrexAtom::AP4_TrexAtom(AP4_UI32 track_id, + AP4_UI32 default_sample_description_index, + AP4_UI32 default_sample_duration, + AP4_UI32 default_sample_size, + AP4_UI32 default_sample_flags) : + AP4_Atom(AP4_ATOM_TYPE_TREX, AP4_FULL_ATOM_HEADER_SIZE+20, 0, 0), + m_TrackId(track_id), + m_DefaultSampleDescriptionIndex(default_sample_description_index), + m_DefaultSampleDuration(default_sample_duration), + m_DefaultSampleSize(default_sample_size), + m_DefaultSampleFlags(default_sample_flags) +{ +} + +/*---------------------------------------------------------------------- +| AP4_TrexAtom::AP4_TrexAtom ++---------------------------------------------------------------------*/ +AP4_TrexAtom::AP4_TrexAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_TREX, size, version, flags) +{ + stream.ReadUI32(m_TrackId); + stream.ReadUI32(m_DefaultSampleDescriptionIndex); + stream.ReadUI32(m_DefaultSampleDuration); + stream.ReadUI32(m_DefaultSampleSize); + stream.ReadUI32(m_DefaultSampleFlags); +} + +/*---------------------------------------------------------------------- +| AP4_TrexAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrexAtom::WriteFields(AP4_ByteStream& stream) +{ + stream.WriteUI32(m_TrackId); + stream.WriteUI32(m_DefaultSampleDescriptionIndex); + stream.WriteUI32(m_DefaultSampleDuration); + stream.WriteUI32(m_DefaultSampleSize); + stream.WriteUI32(m_DefaultSampleFlags); + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_TrexAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_TrexAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("track id", m_TrackId); + inspector.AddField("default sample description index", m_DefaultSampleDescriptionIndex); + inspector.AddField("default sample duration", m_DefaultSampleDuration); + inspector.AddField("default sample size", m_DefaultSampleSize); + inspector.AddField("default sample flags", m_DefaultSampleFlags, AP4_AtomInspector::HINT_HEX); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrexAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrexAtom.h new file mode 100644 index 000000000..42cf1fa2d --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrexAtom.h @@ -0,0 +1,85 @@ +/***************************************************************** +| +| AP4 - trex Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_TREX_ATOM_H_ +#define _AP4_TREX_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4List.h" +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define AP4_TREX_SAMPLE_IS_DIFFERENCE_SAMPLE(_flags) ( (_flags)& + +/*---------------------------------------------------------------------- +| AP4_TrexAtom ++---------------------------------------------------------------------*/ +class AP4_TrexAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_TrexAtom, AP4_Atom) + + // class methods + static AP4_TrexAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_TrexAtom(AP4_UI32 track_id, + AP4_UI32 default_sample_description_index, + AP4_UI32 default_sample_duration, + AP4_UI32 default_sample_size, + AP4_UI32 default_sample_flags); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + AP4_UI32 GetTrackId() { return m_TrackId; } + AP4_UI32 GetDefaultSampleDescriptionIndex() { return m_DefaultSampleDescriptionIndex; } + AP4_UI32 GetDefaultSampleDuration() { return m_DefaultSampleDuration; } + AP4_UI32 GetDefaultSampleSize() { return m_DefaultSampleSize; } + AP4_UI32 GetDefaultSampleFlags() { return m_DefaultSampleFlags; } + +private: + // methods + AP4_TrexAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI32 m_TrackId; + AP4_UI32 m_DefaultSampleDescriptionIndex; + AP4_UI32 m_DefaultSampleDuration; + AP4_UI32 m_DefaultSampleSize; + AP4_UI32 m_DefaultSampleFlags; +}; + +#endif // _AP4_TREX_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrunAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrunAtom.cpp new file mode 100644 index 000000000..e7d4ffc71 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrunAtom.cpp @@ -0,0 +1,243 @@ +/*****************************************************************
+|
+| AP4 - trun Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4TrunAtom.h"
+#include "Ap4Utils.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_TrunAtom)
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom::Create
++---------------------------------------------------------------------*/
+AP4_TrunAtom*
+AP4_TrunAtom::Create(AP4_Size size, AP4_ByteStream& stream)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version > 0) return NULL;
+ return new AP4_TrunAtom(size, version, flags, stream);
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom::ComputeRecordFieldsCount
++---------------------------------------------------------------------*/
+unsigned int
+AP4_TrunAtom::ComputeRecordFieldsCount(AP4_UI32 flags)
+{
+ // count the number of bits set to 1 in the second byte of the flags
+ unsigned int count = 0;
+ for (unsigned int i=0; i<8; i++) {
+ if (flags & (1<<(i+8))) ++count;
+ }
+ return count;
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom::ComputeOptionalFieldsCount
++---------------------------------------------------------------------*/
+unsigned int
+AP4_TrunAtom::ComputeOptionalFieldsCount(AP4_UI32 flags)
+{
+ // count the number of bits set to 1 in the LSB of the flags
+ unsigned int count = 0;
+ for (unsigned int i=0; i<8; i++) {
+ if (flags & (1<<i)) ++count;
+ }
+ return count;
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom::AP4_TrunAtom
++---------------------------------------------------------------------*/
+AP4_TrunAtom::AP4_TrunAtom(AP4_UI32 flags,
+ AP4_SI32 data_offset,
+ AP4_UI32 first_sample_flags) :
+ AP4_Atom(AP4_ATOM_TYPE_TRUN, AP4_FULL_ATOM_HEADER_SIZE+4, 0, flags),
+ m_DataOffset(data_offset),
+ m_FirstSampleFlags(first_sample_flags)
+{
+ m_Size32 += 4*ComputeOptionalFieldsCount(flags);
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom::AP4_TrunAtom
++---------------------------------------------------------------------*/
+AP4_TrunAtom::AP4_TrunAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream) :
+ AP4_Atom(AP4_ATOM_TYPE_TRUN, size, version, flags)
+{
+ AP4_UI32 sample_count = 0;
+ stream.ReadUI32(sample_count);
+
+ // read optional fields
+ int optional_fields_count = (int)ComputeOptionalFieldsCount(flags);
+ if (flags & AP4_TRUN_FLAG_DATA_OFFSET_PRESENT) {
+ AP4_UI32 offset = 0;
+ stream.ReadUI32(offset);
+ m_DataOffset = (AP4_SI32)offset;
+ --optional_fields_count;
+ }
+ if (flags & AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT) {
+ stream.ReadUI32(m_FirstSampleFlags);
+ --optional_fields_count;
+ }
+
+ // discard unknown optional fields
+ for (int i=0; i<optional_fields_count; i++) {
+ AP4_UI32 discard;
+ stream.ReadUI32(discard);
+ }
+
+ int record_fields_count = (int)ComputeRecordFieldsCount(flags);
+ m_Entries.SetItemCount(sample_count);
+ for (unsigned int i=0; i<sample_count; i++) {
+ if (flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) {
+ stream.ReadUI32(m_Entries[i].sample_duration);
+ --record_fields_count;
+ }
+ if (flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) {
+ stream.ReadUI32(m_Entries[i].sample_size);
+ --record_fields_count;
+ }
+ if (flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) {
+ stream.ReadUI32(m_Entries[i].sample_flags);
+ --record_fields_count;
+ }
+ if (flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
+ stream.ReadUI32(m_Entries[i].sample_composition_time_offset);
+ --record_fields_count;
+ }
+
+ // skip unknown fields
+ for (int j=0;j<record_fields_count; j++) {
+ AP4_UI32 discard;
+ stream.ReadUI32(discard);
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_TrunAtom::WriteFields(AP4_ByteStream& stream)
+{
+ AP4_Result result;
+
+ result = stream.WriteUI32(m_Entries.ItemCount());
+ if (AP4_FAILED(result)) return result;
+ if (m_Flags & AP4_TRUN_FLAG_DATA_OFFSET_PRESENT) {
+ result = stream.WriteUI32((AP4_UI32)m_DataOffset);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT) {
+ result = stream.WriteUI32(m_FirstSampleFlags);
+ if (AP4_FAILED(result)) return result;
+ }
+ AP4_UI32 sample_count = m_Entries.ItemCount();
+ for (unsigned int i=0; i<sample_count; i++) {
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) {
+ result = stream.WriteUI32(m_Entries[i].sample_duration);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) {
+ result = stream.WriteUI32(m_Entries[i].sample_size);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) {
+ result = stream.WriteUI32(m_Entries[i].sample_flags);
+ if (AP4_FAILED(result)) return result;
+ }
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
+ stream.WriteUI32(m_Entries[i].sample_composition_time_offset);
+ if (AP4_FAILED(result)) return result;
+ }
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_TrunAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("sample count", m_Entries.ItemCount());
+ if (m_Flags & AP4_TRUN_FLAG_DATA_OFFSET_PRESENT) {
+ inspector.AddField("data offset", m_DataOffset);
+ }
+ if (m_Flags & AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT) {
+ inspector.AddField("first sample flags", m_FirstSampleFlags, AP4_AtomInspector::HINT_HEX);
+ }
+ if (inspector.GetVerbosity() >= 1) {
+ AP4_UI32 sample_count = m_Entries.ItemCount();
+ for (unsigned int i=0; i<sample_count; i++) {
+ char header[32];
+ AP4_FormatString(header, sizeof(header), "entry %04d", i);
+ char v0[32];
+ char v1[32];
+ char v2[32];
+ char v3[64];
+ const char* s0 = "";
+ const char* s1 = "";
+ const char* s2 = "";
+ const char* s3 = "";
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) {
+ AP4_FormatString(v0, sizeof(v0), "sample duration:%d", m_Entries[i].sample_duration);
+ s0 = v0;
+ }
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) {
+ AP4_FormatString(v1, sizeof(v1), "sample size:%d", m_Entries[i].sample_size);
+ s1 = v1;
+ }
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) {
+ AP4_FormatString(v2, sizeof(v2), "sample flags:%x", m_Entries[i].sample_flags);
+ s2 = v2;
+ }
+ if (m_Flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
+ AP4_FormatString(v3, sizeof(v3), "sample composition time offset:%d", m_Entries[i].sample_composition_time_offset);
+ s3 = v3;
+ }
+ char value[128];
+ AP4_FormatString(value, sizeof(value), "%s %s %s %s", s0, s1, s2, s3);
+ inspector.AddField(header, value);
+ }
+ }
+
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrunAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrunAtom.h new file mode 100644 index 000000000..9bdc382b3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4TrunAtom.h @@ -0,0 +1,95 @@ +/*****************************************************************
+|
+| AP4 - trun Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_TRUN_ATOM_H_
+#define _AP4_TRUN_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+#include "Ap4Array.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_UI32 AP4_TRUN_FLAG_DATA_OFFSET_PRESENT = 0x0001;
+const AP4_UI32 AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT = 0x0004;
+const AP4_UI32 AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT = 0x0100;
+const AP4_UI32 AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT = 0x0200;
+const AP4_UI32 AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT = 0x0400;
+const AP4_UI32 AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT = 0x0800;
+
+/*----------------------------------------------------------------------
+| AP4_TrunAtom
++---------------------------------------------------------------------*/
+class AP4_TrunAtom : public AP4_Atom
+{
+public:
+ AP4_IMPLEMENT_DYNAMIC_CAST(AP4_TrunAtom)
+
+ // types
+ struct Entry {
+ Entry() : sample_duration(0), sample_size(0), sample_flags(0), sample_composition_time_offset(0) {}
+ AP4_UI32 sample_duration;
+ AP4_UI32 sample_size;
+ AP4_UI32 sample_flags;
+ AP4_UI32 sample_composition_time_offset;
+ };
+
+ // class methods
+ static AP4_TrunAtom* Create(AP4_Size size, AP4_ByteStream& stream);
+ static unsigned int ComputeOptionalFieldsCount(AP4_UI32 flags);
+ static unsigned int ComputeRecordFieldsCount(AP4_UI32 flags);
+
+ // methods
+ AP4_TrunAtom(AP4_UI32 flags,
+ AP4_SI32 data_offset,
+ AP4_UI32 first_sample_flags);
+ virtual AP4_Result InspectFields(AP4_AtomInspector& inspector);
+ virtual AP4_Result WriteFields(AP4_ByteStream& stream);
+
+ // accessors
+ AP4_SI32 GetDataOffset() { return m_DataOffset; }
+ AP4_UI32 GetFirstSampleFlags() { return m_FirstSampleFlags; }
+ const AP4_Array<Entry>& GetEntries() { return m_Entries; }
+
+private:
+ // methods
+ AP4_TrunAtom(AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream);
+
+ // members
+ AP4_SI32 m_DataOffset;
+ AP4_UI32 m_FirstSampleFlags;
+ AP4_Array<Entry> m_Entries;
+};
+
+#endif // _AP4_TRUN_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Types.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Types.h new file mode 100644 index 000000000..86409c337 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Types.h @@ -0,0 +1,76 @@ +/***************************************************************** +| +| AP4 - Shared Types +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_TYPES_H_ +#define _AP4_TYPES_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Config.h" + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +typedef int AP4_Result; +typedef unsigned int AP4_Flags; +typedef unsigned int AP4_Mask; +typedef unsigned int AP4_Cardinal; +typedef unsigned int AP4_Ordinal; +typedef unsigned int AP4_UI32; +typedef signed int AP4_SI32; +typedef unsigned short AP4_UI16; +typedef signed short AP4_SI16; +typedef unsigned char AP4_UI08; +typedef unsigned char AP4_Byte; +typedef unsigned long AP4_Size; + +// the rest depends on whether the platform supports 64-bit integers +#if defined(AP4_CONFIG_HAVE_INT64) + // we have 64-bit integers + typedef AP4_CONFIG_INT64_TYPE AP4_SI64; + typedef unsigned AP4_CONFIG_INT64_TYPE AP4_UI64; + typedef unsigned AP4_CONFIG_INT64_TYPE AP4_LargeSize; + typedef AP4_CONFIG_INT64_TYPE AP4_Offset; + typedef unsigned AP4_CONFIG_INT64_TYPE AP4_Position; +#else + // use only 32-bit integers + typedef struct { + AP4_UI32 hi; + AP4_UI32 lo; + } AP4_UI64, AP4_SI64; + typedef unsigned long AP4_LargeSize; + typedef long AP4_Offset; + typedef unsigned long AP4_Position; +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif // _AP4_TYPES_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UrlAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UrlAtom.cpp new file mode 100644 index 000000000..8659d9837 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UrlAtom.cpp @@ -0,0 +1,115 @@ +/***************************************************************** +| +| AP4 - url Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4UrlAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_UrlAtom::Create ++---------------------------------------------------------------------*/ +AP4_UrlAtom* +AP4_UrlAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_UrlAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_UrlAtom::AP4_UrlAtom ++---------------------------------------------------------------------*/ +AP4_UrlAtom::AP4_UrlAtom() : + AP4_Atom(AP4_ATOM_TYPE_URL, AP4_FULL_ATOM_HEADER_SIZE, 0, 1) +{ +} + +/*---------------------------------------------------------------------- +| AP4_UrlAtom::AP4_UrlAtom ++---------------------------------------------------------------------*/ +AP4_UrlAtom::AP4_UrlAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_URL, size, version, flags) +{ + if ((m_Flags & 1) == 0) { + // not self contained + AP4_Size str_size = size-AP4_FULL_ATOM_HEADER_SIZE; + if (str_size > 0) { + char* str = new char[str_size]; + stream.Read(str, str_size); + str[str_size-1] = '\0'; // force null-termination + m_Url = str; + delete[] str; + } + } +} + +/*---------------------------------------------------------------------- +| AP4_UrlAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_UrlAtom::WriteFields(AP4_ByteStream& stream) +{ + if (m_Flags & 1) { + // local ref (self contained) + return AP4_SUCCESS; + } else { + // url (not self contained) + if (m_Size32 > AP4_FULL_ATOM_HEADER_SIZE) { + AP4_Result result = stream.Write(m_Url.GetChars(), m_Url.GetLength()+1); + if (AP4_FAILED(result)) return result; + + // pad with zeros if necessary + AP4_Size padding = m_Size32-(AP4_FULL_ATOM_HEADER_SIZE+m_Url.GetLength()+1); + while (padding--) stream.WriteUI08(0); + } + return AP4_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| AP4_UrlAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_UrlAtom::InspectFields(AP4_AtomInspector& inspector) +{ + if (m_Flags & 1) { + inspector.AddField("location", "[local to file]"); + } else { + inspector.AddField("location", m_Url.GetChars()); + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UrlAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UrlAtom.h new file mode 100644 index 000000000..3e354f70c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UrlAtom.h @@ -0,0 +1,63 @@ +/***************************************************************** +| +| AP4 - url Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| + ****************************************************************/ + +#ifndef _AP4_URL_ATOM_H_ +#define _AP4_URL_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4String.h" + +/*---------------------------------------------------------------------- +| AP4_UrlAtom ++---------------------------------------------------------------------*/ +class AP4_UrlAtom : public AP4_Atom +{ +public: + // class methods + static AP4_UrlAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_UrlAtom(); // local ref only (no URL string) + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_UrlAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_String m_Url; +}; + +#endif // _AP4_URL_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Utils.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Utils.cpp new file mode 100644 index 000000000..ef7834a3c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Utils.cpp @@ -0,0 +1,266 @@ +/*****************************************************************
+|
+| AP4 - Utilities
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Utils.h"
+
+/*----------------------------------------------------------------------
+| AP4_BytesToDoubleBE
++---------------------------------------------------------------------*/
+double
+AP4_BytesToDoubleBE(const unsigned char* bytes)
+{
+ AP4_UI64 i_value = AP4_BytesToUInt64BE(bytes);
+ void* v_value = reinterpret_cast<void*>(&i_value);
+ double* d_value = reinterpret_cast<double*>(v_value);
+
+ return *d_value;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesToUInt64BE
++---------------------------------------------------------------------*/
+AP4_UI64
+AP4_BytesToUInt64BE(const unsigned char* bytes)
+{
+ return
+ ( ((AP4_UI64)bytes[0])<<56 ) |
+ ( ((AP4_UI64)bytes[1])<<48 ) |
+ ( ((AP4_UI64)bytes[2])<<40 ) |
+ ( ((AP4_UI64)bytes[3])<<32 ) |
+ ( ((AP4_UI64)bytes[4])<<24 ) |
+ ( ((AP4_UI64)bytes[5])<<16 ) |
+ ( ((AP4_UI64)bytes[6])<<8 ) |
+ ( ((AP4_UI64)bytes[7]) );
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesFromDoubleBE
++---------------------------------------------------------------------*/
+void
+AP4_BytesFromDoubleBE(unsigned char* bytes, double value)
+{
+ void* v_value = reinterpret_cast<void*>(&value);
+ AP4_UI64* i_value = reinterpret_cast<AP4_UI64*>(v_value);
+
+ AP4_BytesFromUInt64BE(bytes, *i_value);
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesFromUInt64BE
++---------------------------------------------------------------------*/
+void
+AP4_BytesFromUInt64BE(unsigned char* bytes, AP4_UI64 value)
+{
+ bytes[0] = (unsigned char)(value >> 56);
+ bytes[1] = (unsigned char)(value >> 48);
+ bytes[2] = (unsigned char)(value >> 40);
+ bytes[3] = (unsigned char)(value >> 32);
+ bytes[4] = (unsigned char)(value >> 24);
+ bytes[5] = (unsigned char)(value >> 16);
+ bytes[6] = (unsigned char)(value >> 8);
+ bytes[7] = (unsigned char)(value );
+}
+
+/*----------------------------------------------------------------------
+| AP4_DurationMsFromUnits
++---------------------------------------------------------------------*/
+AP4_UI32
+AP4_DurationMsFromUnits(AP4_UI64 units, AP4_UI32 units_per_second)
+{
+ if (units_per_second == 0) return 0;
+ return (AP4_UI32)(((double)units*1000.0)/(double)units_per_second);
+}
+
+/*----------------------------------------------------------------------
+| AP4_ConvertTime
++---------------------------------------------------------------------*/
+AP4_UI64
+AP4_ConvertTime(AP4_UI64 time_value,
+ AP4_UI32 from_time_scale,
+ AP4_UI32 to_time_scale)
+{
+ if (from_time_scale == 0) return 0;
+ double ratio = (double)to_time_scale/(double)from_time_scale;
+ return ((AP4_UI64)((double)time_value*ratio));
+}
+
+/*----------------------------------------------------------------------
+| AP4_FormatFourChars
++---------------------------------------------------------------------*/
+void
+AP4_FormatFourChars(char* str, AP4_UI32 value) {
+ str[0] = (value >> 24) & 0xFF;
+ str[1] = (value >> 16) & 0xFF;
+ str[2] = (value >> 8) & 0xFF;
+ str[3] = (value ) & 0xFF;
+ str[4] = '\0';
+}
+
+/*----------------------------------------------------------------------
+| AP4_FormatFourCharsPrintable
++---------------------------------------------------------------------*/
+void
+AP4_FormatFourCharsPrintable(char* str, AP4_UI32 value) {
+ AP4_FormatFourChars(str, value);
+ for (int i=0; i<4; i++) {
+ if (str[i]<' ' || str[i] >= 127) {
+ str[i] = '.';
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_SplitArgs
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SplitArgs(char* arg, char*& arg0, char*& arg1)
+{
+ arg0 = arg;
+ char* c = arg;
+ while (*c != 0 && *c != ':') {
+ c++;
+ }
+ if (*c == ':') {
+ *c++ = '\0';
+ arg1 = c;
+ return AP4_SUCCESS;
+ } else {
+ return AP4_FAILURE;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_SplitArgs
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_SplitArgs(char* arg, char*& arg0, char*& arg1, char*& arg2)
+{
+ AP4_Result result = AP4_SplitArgs(arg, arg0, arg1);
+ if (AP4_FAILED(result)) return result;
+ return AP4_SplitArgs(arg1, arg1, arg2);
+}
+
+/*----------------------------------------------------------------------
+| AP4_HexNibble
++---------------------------------------------------------------------*/
+unsigned char
+AP4_HexNibble(char c)
+{
+ switch (c) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': case 'A': return 10;
+ case 'b': case 'B': return 11;
+ case 'c': case 'C': return 12;
+ case 'd': case 'D': return 13;
+ case 'e': case 'E': return 14;
+ case 'f': case 'F': return 15;
+ default: return 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_NibbleHex
++---------------------------------------------------------------------*/
+char
+AP4_NibbleHex(unsigned int nibble)
+{
+ if (nibble < 10) {
+ return '0'+nibble;
+ } else if (nibble < 16) {
+ return 'A'+(nibble-10);
+ } else {
+ return ' ';
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_ParseHex
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_ParseHex(const char* hex, unsigned char* bytes, unsigned int count)
+{
+ if (AP4_StringLength(hex) != 2*count) return AP4_ERROR_INVALID_PARAMETERS;
+ for (unsigned int i=0; i<count; i++) {
+ bytes[i] = (AP4_HexNibble(hex[2*i]) << 4) | (AP4_HexNibble(hex[2*i+1]));
+ }
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_FormatHex
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_FormatHex(const AP4_UI08* data, unsigned int data_size, char* hex)
+{
+ for (unsigned int i=0; i<data_size; i++) {
+ *hex++ = AP4_NibbleHex(data[i]>>4);
+ *hex++ = AP4_NibbleHex(data[i]&0x0F);
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BitWriter::Write
++---------------------------------------------------------------------*/
+void
+AP4_BitWriter::Write(AP4_UI32 bits, unsigned int bit_count)
+{
+ unsigned char* data = m_Data;
+ if (m_BitCount+bit_count > m_DataSize*8) return;
+ data += m_BitCount/8;
+ unsigned int space = 8-(m_BitCount%8);
+ while (bit_count) {
+ unsigned int mask = bit_count==32 ? 0xFFFFFFFF : ((1<<bit_count)-1);
+ if (bit_count <= space) {
+ *data |= ((bits&mask) << (space-bit_count));
+ m_BitCount += bit_count;
+ return;
+ } else {
+ *data |= ((bits&mask) >> (bit_count-space));
+ ++data;
+ m_BitCount += space;
+ bit_count -= space;
+ space = 8;
+ }
+ }
+}
+
+
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Utils.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Utils.h new file mode 100644 index 000000000..e2d3b6c93 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Utils.h @@ -0,0 +1,212 @@ +/*****************************************************************
+|
+| AP4 - Utilities
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+#ifndef _AP4_UTILS_H_
+#define _AP4_UTILS_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Config.h"
+#include "Ap4Types.h"
+#include "Ap4Results.h"
+#include "Ap4Config.h"
+
+/*----------------------------------------------------------------------
+| non-inline functions
++---------------------------------------------------------------------*/
+double AP4_BytesToDoubleBE(const unsigned char* bytes);
+AP4_UI64 AP4_BytesToUInt64BE(const unsigned char* bytes);
+void AP4_BytesFromDoubleBE(unsigned char* bytes, double value);
+void AP4_BytesFromUInt64BE(unsigned char* bytes, AP4_UI64 value);
+
+/*----------------------------------------------------------------------
+| AP4_BytesToUInt32BE
++---------------------------------------------------------------------*/
+inline AP4_UI32
+AP4_BytesToUInt32BE(const unsigned char* bytes)
+{
+ return
+ ( ((AP4_UI32)bytes[0])<<24 ) |
+ ( ((AP4_UI32)bytes[1])<<16 ) |
+ ( ((AP4_UI32)bytes[2])<<8 ) |
+ ( ((AP4_UI32)bytes[3]) );
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesToInt32BE
++---------------------------------------------------------------------*/
+inline AP4_SI32
+AP4_BytesToInt32BE(const unsigned char* bytes)
+{
+ return AP4_BytesToUInt32BE(bytes);
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesToUInt24BE
++---------------------------------------------------------------------*/
+inline AP4_UI32
+AP4_BytesToUInt24BE(const unsigned char* bytes)
+{
+ return
+ ( ((AP4_UI32)bytes[0])<<16 ) |
+ ( ((AP4_UI32)bytes[1])<<8 ) |
+ ( ((AP4_UI32)bytes[2]) );
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesToInt16BE
++---------------------------------------------------------------------*/
+inline AP4_UI16
+AP4_BytesToUInt16BE(const unsigned char* bytes)
+{
+ return
+ ( ((AP4_UI16)bytes[0])<<8 ) |
+ ( ((AP4_UI16)bytes[1]) );
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesToInt16BE
++---------------------------------------------------------------------*/
+inline AP4_SI16
+AP4_BytesToInt16BE(const unsigned char* bytes)
+{
+ return (AP4_SI16)AP4_BytesToUInt16BE(bytes);
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesFromUInt32BE
++---------------------------------------------------------------------*/
+inline void
+AP4_BytesFromUInt32BE(unsigned char* bytes, AP4_UI32 value)
+{
+ bytes[0] = (unsigned char)(value >> 24);
+ bytes[1] = (unsigned char)(value >> 16);
+ bytes[2] = (unsigned char)(value >> 8);
+ bytes[3] = (unsigned char)(value );
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesFromUInt24BE
++---------------------------------------------------------------------*/
+inline void
+AP4_BytesFromUInt24BE(unsigned char* bytes, AP4_UI32 value)
+{
+ bytes[0] = (unsigned char)(value >> 16);
+ bytes[1] = (unsigned char)(value >> 8);
+ bytes[2] = (unsigned char)(value );
+}
+
+/*----------------------------------------------------------------------
+| AP4_BytesFromUInt16BE
++---------------------------------------------------------------------*/
+inline void
+AP4_BytesFromUInt16BE(unsigned char* bytes, AP4_UI16 value)
+{
+ bytes[0] = (unsigned char)(value >> 8);
+ bytes[1] = (unsigned char)(value );
+}
+
+/*----------------------------------------------------------------------
+| time functions
++---------------------------------------------------------------------*/
+AP4_UI32 AP4_DurationMsFromUnits(AP4_UI64 units,
+ AP4_UI32 units_per_second);
+AP4_UI64 AP4_ConvertTime(AP4_UI64 time_value,
+ AP4_UI32 from_time_scale,
+ AP4_UI32 to_time_scale);
+
+/*----------------------------------------------------------------------
+| string utils
++---------------------------------------------------------------------*/
+#if defined (AP4_CONFIG_HAVE_STDIO_H)
+#include <stdio.h>
+#endif
+
+#if defined (AP4_CONFIG_HAVE_SNPRINTF)
+#define AP4_FormatString AP4_snprintf
+#else
+int AP4_FormatString(char* str, AP4_Size size, const char* format, ...);
+#endif
+#if defined(AP4_CONFIG_HAVE_VSNPRINTF)
+#define AP4_FormatStringVN(s,c,f,a) AP4_vsnprintf(s,c,f,a)
+#else
+extern int AP4_FormatStringVN(char *buffer, size_t count, const char *format, va_list argptr);
+#endif
+
+#if defined (AP4_CONFIG_HAVE_STRING_H)
+#include <string.h>
+#define AP4_StringLength(x) strlen(x)
+#define AP4_CopyMemory(x,y,z) memcpy(x,y,z)
+#define AP4_CompareMemory(x, y, z) memcmp(x, y, z)
+#define AP4_SetMemory(x,y,z) memset(x,y,z)
+#define AP4_CompareStrings(x,y) strcmp(x,y)
+#endif
+
+unsigned char AP4_HexNibble(char c);
+char AP4_NibbleHex(unsigned int nibble);
+void AP4_FormatFourChars(char* str, AP4_UI32 value);
+void AP4_FormatFourCharsPrintable(char* str, AP4_UI32 value);
+AP4_Result
+AP4_ParseHex(const char* hex, unsigned char* bytes, unsigned int count);
+AP4_Result
+AP4_FormatHex(const AP4_UI08* data, unsigned int data_size, char* hex);
+AP4_Result
+AP4_SplitArgs(char* arg, char*& arg0, char*& arg1, char*& arg2);
+AP4_Result
+AP4_SplitArgs(char* arg, char*& arg0, char*& arg1);
+
+/*----------------------------------------------------------------------
+| AP4_BitWriter
++---------------------------------------------------------------------*/
+class AP4_BitWriter
+{
+public:
+ AP4_BitWriter(AP4_Size size) : m_DataSize(size), m_BitCount(0) {
+ if (size) {
+ m_Data = new unsigned char[size];
+ AP4_SetMemory(m_Data, 0, size);
+ } else {
+ m_Data = NULL;
+ }
+ }
+ ~AP4_BitWriter() { delete m_Data; }
+
+ void Write(AP4_UI32 bits, unsigned int bit_count);
+
+ unsigned int GetBitCount() { return m_BitCount; }
+ const unsigned char* GetData() { return m_Data; }
+
+private:
+ unsigned char* m_Data;
+ unsigned int m_DataSize;
+ unsigned int m_BitCount;
+};
+
+
+#endif // _AP4_UTILS_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UuidAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UuidAtom.cpp new file mode 100644 index 000000000..e71eced66 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UuidAtom.cpp @@ -0,0 +1,193 @@ +/*****************************************************************
+|
+| AP4 - UUID Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Types.h"
+#include "Ap4UuidAtom.h"
+#include "Ap4Utils.h"
+
+/*----------------------------------------------------------------------
+| AP4_UuidAtom::AP4_UuidAtom
++---------------------------------------------------------------------*/
+AP4_UuidAtom::AP4_UuidAtom(AP4_UI64 size, const AP4_UI08* uuid) :
+ AP4_Atom(AP4_ATOM_TYPE_UUID, size)
+{
+ AP4_CopyMemory(m_Uuid, uuid, 16);
+}
+
+/*----------------------------------------------------------------------
+| AP4_UuidAtom::AP4_UuidAtom
++---------------------------------------------------------------------*/
+AP4_UuidAtom::AP4_UuidAtom(AP4_UI64 size, const AP4_UI08* uuid, AP4_UI32 version, AP4_UI32 flags) :
+ AP4_Atom(AP4_ATOM_TYPE_UUID, size, false, version, flags)
+{
+ AP4_CopyMemory(m_Uuid, uuid, 16);
+}
+
+/*----------------------------------------------------------------------
+| AP4_UuidAtom::AP4_UuidAtom
++---------------------------------------------------------------------*/
+AP4_UuidAtom::AP4_UuidAtom(AP4_UI64 size, bool is_full, AP4_ByteStream& stream) :
+ AP4_Atom(AP4_ATOM_TYPE_UUID, size)
+{
+ if (is_full) {
+ m_IsFull = true;
+ ReadFullHeader(stream, m_Version, m_Flags);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_UuidAtom::GetHeaderSize
++---------------------------------------------------------------------*/
+AP4_Size
+AP4_UuidAtom::GetHeaderSize() const
+{
+ return (m_IsFull ? AP4_FULL_UUID_ATOM_HEADER_SIZE : AP4_UUID_ATOM_HEADER_SIZE)+(m_Size32==1?8:0);
+}
+
+/*----------------------------------------------------------------------
+| AP4_UuidAtom::WriteHeader
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_UuidAtom::WriteHeader(AP4_ByteStream& stream)
+{
+ AP4_Result result;
+
+ // write the size
+ result = stream.WriteUI32(m_Size32);
+ if (AP4_FAILED(result)) return result;
+
+ // write the type
+ result = stream.WriteUI32(m_Type);
+ if (AP4_FAILED(result)) return result;
+
+ // handle 64-bit sizes
+ if (m_Size32 == 1) {
+ result = stream.WriteUI64(m_Size64);
+ if (AP4_FAILED(result)) return result;
+ }
+
+ // write the extended type
+ result = stream.Write(m_Uuid, 16);
+ if (AP4_FAILED(result)) return result;
+
+ // for full atoms, write version and flags
+ if (m_IsFull) {
+ result = stream.WriteUI08(m_Version);
+ if (AP4_FAILED(result)) return result;
+ result = stream.WriteUI24(m_Flags);
+ if (AP4_FAILED(result)) return result;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_UuidAtom::InspectHeader
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_UuidAtom::InspectHeader(AP4_AtomInspector& inspector)
+{
+ char uuid[37];
+ uuid[36] = '\0';
+ char* dst = uuid;
+ for (unsigned int i=0; i<16; i++) {
+ *dst++ = AP4_NibbleHex(m_Uuid[i]>>4);
+ *dst++ = AP4_NibbleHex(m_Uuid[i]&0x0F);
+ if (i == 5 || i == 7 || i == 9 || i == 11) *dst++ = '-';
+ }
+
+ // write atom name
+ char name[7];
+ name[0] = '[';
+ AP4_FormatFourCharsPrintable(&name[1], m_Type);
+ name[5] = ']';
+ name[6] = '\0';
+ char header[128];
+ char extra[32] = "";
+ if (m_IsFull) {
+ if (m_Version && m_Flags) {
+ AP4_FormatString(extra, sizeof(extra),
+ ", version=%d, flags=%x",
+ m_Version,
+ m_Flags);
+ } else if (m_Version) {
+ AP4_FormatString(extra, sizeof(extra),
+ ", version=%d",
+ m_Version);
+ } else if (m_Flags) {
+ AP4_FormatString(extra, sizeof(extra),
+ ", flags=%x",
+ m_Flags);
+ }
+ }
+ AP4_FormatString(header, sizeof(header),
+ "{%s} size=%ld+%lld%s",
+ uuid,
+ GetHeaderSize(),
+ GetSize()-GetHeaderSize(),
+ extra);
+ inspector.StartElement(name, header);
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_UnknownUuidAtom::AP4_UnknownUuidAtom
++---------------------------------------------------------------------*/
+AP4_UnknownUuidAtom::AP4_UnknownUuidAtom(AP4_UI64 size, AP4_ByteStream& stream) :
+ AP4_UuidAtom(size, false, stream)
+{
+ // store the data
+ m_Data.SetDataSize((AP4_Size)size-GetHeaderSize());
+ stream.Read(m_Data.UseData(), m_Data.GetDataSize());
+}
+
+/*----------------------------------------------------------------------
+| AP4_UnknownUuidAtom::AP4_UnknownUuidAtom
++---------------------------------------------------------------------*/
+AP4_UnknownUuidAtom::AP4_UnknownUuidAtom(AP4_UI64 size, const AP4_UI08* uuid, AP4_ByteStream& stream) :
+ AP4_UuidAtom(size, uuid)
+{
+ // store the data
+ m_Data.SetDataSize((AP4_Size)size-GetHeaderSize());
+ stream.Read(m_Data.UseData(), m_Data.GetDataSize());
+}
+
+/*----------------------------------------------------------------------
+| AP4_UnknownUuidAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_UnknownUuidAtom::WriteFields(AP4_ByteStream& stream)
+{
+ // write the data
+ return stream.Write(m_Data.GetData(), m_Data.GetDataSize());
+}
+
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UuidAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UuidAtom.h new file mode 100644 index 000000000..2c425193a --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4UuidAtom.h @@ -0,0 +1,95 @@ +/*****************************************************************
+|
+| AP4 - UUID Atoms
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+ ****************************************************************/
+/**
+* @file
+* @brief UUID Atoms
+*/
+
+#ifndef _AP4_UUID_ATOM_H_
+#define _AP4_UUID_ATOM_H_
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4Atom.h"
+#include "Ap4ByteStream.h"
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_UI32 AP4_UUID_ATOM_HEADER_SIZE = AP4_ATOM_HEADER_SIZE+16;
+const AP4_UI32 AP4_FULL_UUID_ATOM_HEADER_SIZE = AP4_FULL_ATOM_HEADER_SIZE+16;
+
+/*----------------------------------------------------------------------
+| AP4_UuidAtom
++---------------------------------------------------------------------*/
+/**
+ * Base class for uuid atoms.
+ */
+class AP4_UuidAtom : public AP4_Atom {
+public:
+ // constructor and destructor
+ virtual ~AP4_UuidAtom() {};
+
+ // methods
+ virtual AP4_Size GetHeaderSize() const;
+ virtual AP4_Result WriteHeader(AP4_ByteStream& stream);
+ virtual AP4_Result InspectHeader(AP4_AtomInspector& inspector);
+
+ // accessors
+ const AP4_UI08* GetUuid() { return m_Uuid; }
+
+protected:
+ // members
+ AP4_UuidAtom(AP4_UI64 size, const AP4_UI08* uuid);
+ AP4_UuidAtom(AP4_UI64 size, const AP4_UI08* uuid, AP4_UI32 version, AP4_UI32 flags);
+ AP4_UuidAtom(AP4_UI64 size, bool is_full, AP4_ByteStream& stream);
+ AP4_UI08 m_Uuid[16];
+};
+
+/*----------------------------------------------------------------------
+| AP4_UnknownUuidAtom
++---------------------------------------------------------------------*/
+/**
+ * Unknown uuid atoms.
+ */
+class AP4_UnknownUuidAtom : public AP4_UuidAtom {
+public:
+ // constructors
+ AP4_UnknownUuidAtom(AP4_UI64 size, AP4_ByteStream& stream);
+ AP4_UnknownUuidAtom(AP4_UI64 size, const AP4_UI08* uuid, AP4_ByteStream& stream);
+
+ // methods
+ virtual AP4_Result WriteFields(AP4_ByteStream& stream);
+
+protected:
+ // members
+ AP4_DataBuffer m_Data;
+};
+
+#endif // _AP4_UUID_ATOM_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Version.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Version.h new file mode 100644 index 000000000..f93fa5f3f --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4Version.h @@ -0,0 +1,43 @@ +/*****************************************************************
+|
+| AP4 - Version Numbers
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+#ifndef _AP4_VERSION_H_
+#define _AP4_VERSION_H_
+
+/*----------------------------------------------------------------------
+| version constants
++---------------------------------------------------------------------*/
+/**
+ * Version number of the SDK
+ */
+#define AP4_VERSION 0x01020200
+#define AP4_VERSION_STRING "1.2.2.0"
+
+#endif // _AP4_VERSION_H_
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4VmhdAtom.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4VmhdAtom.cpp new file mode 100644 index 000000000..0aaf37c72 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4VmhdAtom.cpp @@ -0,0 +1,107 @@ +/***************************************************************** +| +| AP4 - vmhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4VmhdAtom.h" +#include "Ap4AtomFactory.h" +#include "Ap4Utils.h" +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| AP4_VmhdAtom::Create ++---------------------------------------------------------------------*/ +AP4_VmhdAtom* +AP4_VmhdAtom::Create(AP4_Size size, AP4_ByteStream& stream) +{ + AP4_UI32 version; + AP4_UI32 flags; + if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; + if (version != 0) return NULL; + return new AP4_VmhdAtom(size, version, flags, stream); +} + +/*---------------------------------------------------------------------- +| AP4_VmhdAtom::AP4_VmhdAtom ++---------------------------------------------------------------------*/ +AP4_VmhdAtom::AP4_VmhdAtom(AP4_UI16 graphics_mode, AP4_UI16 r, AP4_UI16 g, AP4_UI16 b) : + AP4_Atom(AP4_ATOM_TYPE_VMHD, AP4_FULL_ATOM_HEADER_SIZE+8, 0, 0), + m_GraphicsMode(graphics_mode) +{ + m_OpColor[0] = r; + m_OpColor[1] = g; + m_OpColor[2] = b; +} + +/*---------------------------------------------------------------------- +| AP4_VmhdAtom::AP4_VmhdAtom ++---------------------------------------------------------------------*/ +AP4_VmhdAtom::AP4_VmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream) : + AP4_Atom(AP4_ATOM_TYPE_VMHD, size, version, flags) +{ + stream.ReadUI16(m_GraphicsMode); + stream.Read(m_OpColor, sizeof(m_OpColor)); +} + +/*---------------------------------------------------------------------- +| AP4_VmhdAtom::WriteFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_VmhdAtom::WriteFields(AP4_ByteStream& stream) +{ + AP4_Result result; + + // graphics mode + result = stream.WriteUI16(m_GraphicsMode); + if (AP4_FAILED(result)) return result; + + // op color + result = stream.Write(m_OpColor, sizeof(m_OpColor)); + if (AP4_FAILED(result)) return result; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_VmhdAtom::InspectFields ++---------------------------------------------------------------------*/ +AP4_Result +AP4_VmhdAtom::InspectFields(AP4_AtomInspector& inspector) +{ + inspector.AddField("graphics_mode", m_GraphicsMode); + char formatted[16]; + AP4_FormatString(formatted, sizeof(formatted), "%04x,%04x,%04x", + m_OpColor[0], m_OpColor[1], m_OpColor[2]); + inspector.AddField("op_color", formatted); + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4VmhdAtom.h b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4VmhdAtom.h new file mode 100644 index 000000000..6fed056e3 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Core/Ap4VmhdAtom.h @@ -0,0 +1,63 @@ +/***************************************************************** +| +| AP4 - vmhd Atoms +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_VMHD_ATOM_H_ +#define _AP4_VMHD_ATOM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" + +/*---------------------------------------------------------------------- +| AP4_VmhdAtom ++---------------------------------------------------------------------*/ +class AP4_VmhdAtom : public AP4_Atom +{ +public: + // class methods + static AP4_VmhdAtom* Create(AP4_Size size, AP4_ByteStream& stream); + + // methods + AP4_VmhdAtom(AP4_UI16 graphics_mode, AP4_UI16 r, AP4_UI16 g, AP4_UI16 b); + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + +private: + // methods + AP4_VmhdAtom(AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // members + AP4_UI16 m_GraphicsMode; + AP4_UI16 m_OpColor[3]; +}; + +#endif // _AP4_VMHD_ATOM_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4AesBlockCipher.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4AesBlockCipher.cpp new file mode 100644 index 000000000..ef0619901 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4AesBlockCipher.cpp @@ -0,0 +1,1866 @@ +/* +* AES Block cipher +* (c) 2005-2008 Axiomatic Systems,LLC +* Portions (c) 2001, Dr Brian Gladman (see below) +*/ + +/* +------------------------------------------------------------------------- +Copyright (c) 2001, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. +All rights reserved. + +LICENSE TERMS + +The free distribution and use of this software in both source and binary +form is allowed (with or without changes) provided that: + +1. distributions of this source code include the above copyright +notice, this list of conditions and the following disclaimer; + +2. distributions in binary form include the above copyright +notice, this list of conditions and the following disclaimer +in the documentation and/or other associated materials; + +3. the copyright holder's name is not used to endorse products +built using this software without specific written permission. + +DISCLAIMER + +This software is provided 'as is' with no explicit or implied warranties +in respect of its properties, including, but not limited to, correctness +and fitness for purpose. +------------------------------------------------------------------------- +Issue Date: 29/07/2002 +*/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4AesBlockCipher.h" +#include "Ap4Results.h" + +/*---------------------------------------------------------------------- +| AES types ++---------------------------------------------------------------------*/ +typedef AP4_UI32 aes_32t; +typedef AP4_UI08 aes_08t; +typedef unsigned int aes_rval; +struct aes_ctx // the AES context for encryption +{ aes_32t k_sch[4*AP4_AES_BLOCK_SIZE]; // the encryption key schedule + aes_32t n_rnd; // the number of cipher rounds + aes_32t n_blk; // the number of bytes in the state +}; +#define aes_bad 0 // bad function return value +#define aes_good 1 // good function return value + +/*---------------------------------------------------------------------- +| build options ++---------------------------------------------------------------------*/ +#define ENCRYPTION_KEY_SCHEDULE +#define ENCRYPTION +#define DECRYPTION_KEY_SCHEDULE +#define DECRYPTION +#define BLOCK_SIZE AP4_AES_BLOCK_SIZE + +/*---------------------------------------------------------------------- +| options ++---------------------------------------------------------------------*/ +/* START OF CONFIGURATION OPTIONS + + USE OF DEFINES + + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. +*/ + +/* 1. BYTE ORDER IN 32-BIT WORDS + + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the order in which bytes are packed into such words. + The following block of code is an attempt to capture the most obvious + ways in which various environemnts define byte order. It may well fail, + in which case the definitions will need to be set by editing at the + points marked **** EDIT HERE IF NECESSARY **** below. +*/ +#define AES_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define AES_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +#if !defined(AP4_PLATFORM_BYTE_ORDER) +# error AP4_PLATFORM_BYTE_ORDER is not set +#endif + +#if AP4_PLATFORM_BYTE_ORDER == AP4_PLATFORM_BYTE_ORDER_BIG_ENDIAN +#define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN +#elif AP4_PLATFORM_BYTE_ORDER == AP4_PLATFORM_BYTE_ORDER_LITTLE_ENDIAN +#define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN +#else +#error unsupported value for AP4_PLATFORM_BYTE_ORDER +#endif + + + +/* 2. BYTE ORDER WITHIN 32 BIT WORDS + + The fundamental data processing units in Rijndael are 8-bit bytes. The + input, output and key input are all enumerated arrays of bytes in which + bytes are numbered starting at zero and increasing to one less than the + number of bytes in the array in question. This enumeration is only used + for naming bytes and does not imply any adjacency or order relationship + from one byte to another. When these inputs and outputs are considered + as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to + byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. + In this implementation bits are numbered from 0 to 7 starting at the + numerically least significant end of each byte (bit n represents 2^n). + + However, Rijndael can be implemented more efficiently using 32-bit + words by packing bytes into words so that bytes 4*n to 4*n+3 are placed + into word[n]. While in principle these bytes can be assembled into words + in any positions, this implementation only supports the two formats in + which bytes in adjacent positions within words also have adjacent byte + numbers. This order is called big-endian if the lowest numbered bytes + in words have the highest numeric significance and little-endian if the + opposite applies. + + This code can work in either order irrespective of the order used by the + machine on which it runs. Normally the internal byte order will be set + to the order of the processor on which the code is to be run but this + define can be used to reverse this in special situations +*/ +#if 1 +#define INTERNAL_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif defined(AES_LITTLE_ENDIAN) +#define INTERNAL_BYTE_ORDER AES_LITTLE_ENDIAN +#elif defined(AES_BIG_ENDIAN) +#define INTERNAL_BYTE_ORDER AES_BIG_ENDIAN +#endif + +/* 3. FAST INPUT/OUTPUT OPERATIONS. + + On some machines it is possible to improve speed by transferring the + bytes in the input and output arrays to and from the internal 32-bit + variables by addressing these arrays as if they are arrays of 32-bit + words. On some machines this will always be possible but there may + be a large performance penalty if the byte arrays are not aligned on + the normal word boundaries. On other machines this technique will + lead to memory access errors when such 32-bit word accesses are not + properly aligned. The option SAFE_IO avoids such problems but will + often be slower on those machines that support misaligned access + (especially so if care is taken to align the input and output byte + arrays on 32-bit word boundaries). If SAFE_IO is not defined it is + assumed that access to byte arrays as if they are arrays of 32-bit + words will not cause problems when such accesses are misaligned. +*/ +#if 1 +#define SAFE_IO +#endif + +/* 4. LOOP UNROLLING + + The code for encryption and decrytpion cycles through a number of rounds + that can be implemented either in a loop or by expanding the code into a + long sequence of instructions, the latter producing a larger program but + one that will often be much faster. The latter is called loop unrolling. + There are also potential speed advantages in expanding two iterations in + a loop with half the number of iterations, which is called partial loop + unrolling. The following options allow partial or full loop unrolling + to be set independently for encryption and decryption +*/ +#if 0 +#define ENC_UNROLL FULL +#elif 0 +#define ENC_UNROLL PARTIAL +#else +#define ENC_UNROLL NONE +#endif + +#if 0 +#define DEC_UNROLL FULL +#elif 0 +#define DEC_UNROLL PARTIAL +#else +#define DEC_UNROLL NONE +#endif + +/* 5. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are comipled + statically into the binary file. Otherwise they are computed once when + the code is first used. +*/ +#if 1 +#define FIXED_TABLES +#endif + +/* 6. FAST FINITE FIELD OPERATIONS + + If this section is included, tables are used to provide faster finite + field arithmetic (this has no effect if FIXED_TABLES is defined). +*/ +#if 1 +#define FF_TABLES +#endif + +/* 7. INTERNAL STATE VARIABLE FORMAT + + The internal state of Rijndael is stored in a number of local 32-bit + word varaibles which can be defined either as an array or as individual + names variables. Include this section if you want to store these local + variables in arrays. Otherwise individual local variables will be used. +*/ +#if 1 +#define ARRAYS +#endif + +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. +*/ + +#if defined(ARRAYS) +#define s(x,c) x[c] +#else +#define s(x,c) x##c +#endif + +/* 8. VARIABLE BLOCK SIZE SPEED + + This section is only relevant if you wish to use the variable block + length feature of the code. Include this section if you place more + emphasis on speed rather than code size. +*/ +#if 0 +#define FAST_VARIABLE +#endif + +/* 9. INTERNAL TABLE CONFIGURATION + + This cipher proceeds by repeating in a number of cycles known as 'rounds' + which are implemented by a round function which can optionally be speeded + up using tables. The basic tables are each 256 32-bit words, with either + one or four tables being required for each round function depending on + how much speed is required. The encryption and decryption round functions + are different and the last encryption and decrytpion round functions are + different again making four different round functions in all. + + This means that: + 1. Normal encryption and decryption rounds can each use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + 2. The last encryption and decryption rounds can also use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + + Include or exclude the appropriate definitions below to set the number + of tables used by this implementation. +*/ + +#if 1 /* set tables for the normal encryption round */ +#define ENC_ROUND FOUR_TABLES +#elif 0 +#define ENC_ROUND ONE_TABLE +#else +#define ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last encryption round */ +#define LAST_ENC_ROUND FOUR_TABLES +#elif 0 +#define LAST_ENC_ROUND ONE_TABLE +#else +#define LAST_ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the normal decryption round */ +#define DEC_ROUND FOUR_TABLES +#elif 0 +#define DEC_ROUND ONE_TABLE +#else +#define DEC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last decryption round */ +#define LAST_DEC_ROUND FOUR_TABLES +#elif 0 +#define LAST_DEC_ROUND ONE_TABLE +#else +#define LAST_DEC_ROUND NO_TABLES +#endif + +/* The decryption key schedule can be speeded up with tables in the same + way that the round functions can. Include or exclude the following + defines to set this requirement. +*/ +#if 1 +#define KEY_SCHED FOUR_TABLES +#elif 0 +#define KEY_SCHED ONE_TABLE +#else +#define KEY_SCHED NO_TABLES +#endif + +/* END OF CONFIGURATION OPTIONS */ + +#define NO_TABLES 0 /* DO NOT CHANGE */ +#define ONE_TABLE 1 /* DO NOT CHANGE */ +#define FOUR_TABLES 4 /* DO NOT CHANGE */ +#define NONE 0 /* DO NOT CHANGE */ +#define PARTIAL 1 /* DO NOT CHANGE */ +#define FULL 2 /* DO NOT CHANGE */ + +#if defined(BLOCK_SIZE) && ((BLOCK_SIZE & 3) || BLOCK_SIZE < 16 || BLOCK_SIZE > 32) +#error An illegal block size has been specified. +#endif + +#if !defined(BLOCK_SIZE) +#define RC_LENGTH 29 +#else +#define RC_LENGTH 5 * BLOCK_SIZE / 4 - (BLOCK_SIZE == 16 ? 10 : 11) +#endif + +/* Disable at least some poor combinations of options */ + +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND ONE_TABLE +#endif + +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +#undef ENC_UNROLL +#define ENC_UNROLL NONE +#endif + +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND ONE_TABLE +#endif + +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +#undef DEC_UNROLL +#define DEC_UNROLL NONE +#endif + +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word + + NOTE: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ + +#if (INTERNAL_BYTE_ORDER == AES_LITTLE_ENDIAN) +#if defined(_MSC_VER) +#define upr(x,n) _lrotl((aes_32t)(x), 8 * (n)) +#else +#define upr(x,n) ((aes_32t)(x) << 8 * (n) | (aes_32t)(x) >> (32 - 8 * (n))) +#endif +#define ups(x,n) ((aes_32t)(x) << 8 * (n)) +#define bval(x,n) ((aes_08t)((x) >> 8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + (((aes_32t)(b3) << 24) | ((aes_32t)(b2) << 16) | ((aes_32t)(b1) << 8) | (b0)) +#endif + +#if (INTERNAL_BYTE_ORDER == AES_BIG_ENDIAN) +#define upr(x,n) ((aes_32t)(x) >> 8 * (n) | (aes_32t)(x) << 32 - 8 * (n)) +#define ups(x,n) ((aes_32t)(x) >> 8 * (n))) +#define bval(x,n) ((aes_08t)((x) >> (24 - 8 * (n)))) +#define bytes2word(b0, b1, b2, b3) \ + (((aes_32t)(b0) << 24) | ((aes_32t)(b1) << 16) | ((aes_32t)(b2) << 8) | (b3)) +#endif + +#if defined(SAFE_IO) + +#define word_in(x) bytes2word((x)[0], (x)[1], (x)[2], (x)[3]) +#define word_out(x,v) { (x)[0] = bval(v,0); (x)[1] = bval(v,1); \ + (x)[2] = bval(v,2); (x)[3] = bval(v,3); } + +#elif (INTERNAL_BYTE_ORDER == PLATFORM_BYTE_ORDER) + +#define word_in(x) *(aes_32t*)(x) +#define word_out(x,v) *(aes_32t*)(x) = (v) + +#else + +#if !defined(bswap_32) +#if !defined(_MSC_VER) +#define _lrotl(x,n) ((((aes_32t)(x)) << n) | (((aes_32t)(x)) >> (32 - n))) +#endif +#define bswap_32(x) ((_lrotl((x),8) & 0x00ff00ff) | (_lrotl((x),24) & 0xff00ff00)) +#endif + +#define word_in(x) bswap_32(*(aes_32t*)(x)) +#define word_out(x,v) *(aes_32t*)(x) = bswap_32(v) + +#endif + +/* the finite field modular polynomial and elements */ + +#define WPOLY 0x011b +#define BPOLY 0x1b + +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + +#define m1 0x80808080 +#define m2 0x7f7f7f7f +#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY)) + +/* The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where FFmulX is used. + +#define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) +#define m4 (0x01010101 * BPOLY) +#define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) +*/ + +/* Work out which tables are needed for the different options */ + +#ifdef AES_ASM +#ifdef ENC_ROUND +#undef ENC_ROUND +#endif +#define ENC_ROUND FOUR_TABLES +#ifdef LAST_ENC_ROUND +#undef LAST_ENC_ROUND +#endif +#define LAST_ENC_ROUND FOUR_TABLES +#ifdef DEC_ROUND +#undef DEC_ROUND +#endif +#define DEC_ROUND FOUR_TABLES +#ifdef LAST_DEC_ROUND +#undef LAST_DEC_ROUND +#endif +#define LAST_DEC_ROUND FOUR_TABLES +#ifdef KEY_SCHED +#undef KEY_SCHED +#define KEY_SCHED FOUR_TABLES +#endif +#endif + +#if defined(ENCRYPTION) || defined(AES_ASM) +#if ENC_ROUND == ONE_TABLE +#define FT1_SET +#elif ENC_ROUND == FOUR_TABLES +#define FT4_SET +#else +#define SBX_SET +#endif +#if LAST_ENC_ROUND == ONE_TABLE +#define FL1_SET +#elif LAST_ENC_ROUND == FOUR_TABLES +#define FL4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif + +#if defined(DECRYPTION) || defined(AES_ASM) +#if DEC_ROUND == ONE_TABLE +#define IT1_SET +#elif DEC_ROUND == FOUR_TABLES +#define IT4_SET +#else +#define ISB_SET +#endif +#if LAST_DEC_ROUND == ONE_TABLE +#define IL1_SET +#elif LAST_DEC_ROUND == FOUR_TABLES +#define IL4_SET +#elif !defined(ISB_SET) +#define ISB_SET +#endif +#endif + +#if defined(ENCRYPTION_KEY_SCHEDULE) || defined(DECRYPTION_KEY_SCHEDULE) +#if KEY_SCHED == ONE_TABLE +#define LS1_SET +#define IM1_SET +#elif KEY_SCHED == FOUR_TABLES +#define LS4_SET +#define IM4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif + +#ifdef FIXED_TABLES +#define prefx static const +#else +#define prefx extern +extern aes_08t tab_init; +void gen_tabs(void); +#endif + +//prefx aes_32t rcon_tab[29]; +// +//#ifdef SBX_SET +//prefx aes_08t s_box[256]; +//#endif +// +//#ifdef ISB_SET +//prefx aes_08t inv_s_box[256]; +//#endif +// +//#ifdef FT1_SET +//prefx aes_32t ft_tab[256]; +//#endif +// +//#ifdef FT4_SET +//prefx aes_32t ft_tab[4][256]; +//#endif +// +//#ifdef FL1_SET +//prefx aes_32t fl_tab[256]; +//#endif +// +//#ifdef FL4_SET +//prefx aes_32t fl_tab[4][256]; +//#endif +// +//#ifdef IT1_SET +//prefx aes_32t it_tab[256]; +//#endif +// +//#ifdef IT4_SET +//prefx aes_32t it_tab[4][256]; +//#endif +// +//#ifdef IL1_SET +//prefx aes_32t il_tab[256]; +//#endif +// +//#ifdef IL4_SET +//prefx aes_32t il_tab[4][256]; +//#endif +// +//#ifdef LS1_SET +//#ifdef FL1_SET +//#undef LS1_SET +//#else +//prefx aes_32t ls_tab[256]; +//#endif +//#endif +// +//#ifdef LS4_SET +//#ifdef FL4_SET +//#undef LS4_SET +//#else +//prefx aes_32t ls_tab[4][256]; +//#endif +//#endif +// +//#ifdef IM1_SET +//prefx aes_32t im_tab[256]; +//#endif +// +//#ifdef IM4_SET +//prefx aes_32t im_tab[4][256]; +//#endif + +/* Set the number of columns in nc. Note that it is important + that nc is a constant which is known at compile time if the + highest speed version of the code is needed. +*/ + +#if defined(BLOCK_SIZE) +#define nc (BLOCK_SIZE >> 2) +#else +#define nc (cx->n_blk >> 2) +#endif + +/* generic definitions of Rijndael macros that use tables */ + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((r-c)&3) + +/* perform forward and inverse column mix operation on four bytes in long word x in */ +/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ + +#define dec_fmvars +#if defined(FM4_SET) /* not currently used */ +#define fwd_mcol(x) four_tables(x,fm_tab,vf1,rf1,0) +#elif defined(FM1_SET) /* not currently used */ +#define fwd_mcol(x) one_table(x,upr,fm_tab,vf1,rf1,0) +#else +#undef dec_fmvars +#define dec_fmvars aes_32t f1, f2; +#define fwd_mcol(x) (f1 = (x), f2 = FFmulX(f1), f2 ^ upr(f1 ^ f2, 3) ^ upr(f1, 2) ^ upr(f1, 1)) +#endif + +#define dec_imvars +#if defined(IM4_SET) +#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) +#elif defined(IM1_SET) +#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0) +#else +#undef dec_imvars +#define dec_imvars aes_32t f2, f4, f8, f9; +#define inv_mcol(x) \ + (f9 = (x), f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \ + f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1)) +#endif + +#if defined(FL4_SET) +#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) +#elif defined(LS4_SET) +#define ls_box(x,c) four_tables(x,ls_tab,vf1,rf2,c) +#elif defined(FL1_SET) +#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c) +#elif defined(LS1_SET) +#define ls_box(x,c) one_table(x,upr,ls_tab,vf1,rf2,c) +#else +#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c) +#endif + +/*---------------------------------------------------------------------- +| tables ++---------------------------------------------------------------------*/ +#if defined(FIXED_TABLES) || !defined(FF_TABLES) + +/* finite field arithmetic operations */ + +#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) +#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) +#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ + ^ (((x>>5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#endif + +#if defined(FIXED_TABLES) + +#define sb_data(w) \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) + +#define isb_data(w) \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d), + +#define mm_data(w) \ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) + +#define h0(x) (x) + +/* These defines are used to ensure tables are generated in the + right format depending on the internal byte order required +*/ + +#define w0(p) bytes2word(p, 0, 0, 0) +#define w1(p) bytes2word(0, p, 0, 0) +#define w2(p) bytes2word(0, 0, p, 0) +#define w3(p) bytes2word(0, 0, 0, p) + +/* Number of elements required in this table for different + block and key lengths is: + + Rcon Table key length (bytes) + Length 16 20 24 28 32 + --------------------- + block 16 | 10 9 8 7 7 + length 20 | 14 11 10 9 9 + (bytes) 24 | 19 15 12 11 11 + 28 | 24 19 16 13 13 + 32 | 29 23 19 17 14 + + this table can be a table of bytes if the key schedule + code is adjusted accordingly +*/ + +#define u0(p) bytes2word(f2(p), p, p, f3(p)) +#define u1(p) bytes2word(f3(p), f2(p), p, p) +#define u2(p) bytes2word(p, f3(p), f2(p), p) +#define u3(p) bytes2word(p, p, f3(p), f2(p)) + +#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) +#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) +#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) +#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) + +static const aes_32t rcon_tab[29] = +{ + w0(0x01), w0(0x02), w0(0x04), w0(0x08), + w0(0x10), w0(0x20), w0(0x40), w0(0x80), + w0(0x1b), w0(0x36), w0(0x6c), w0(0xd8), + w0(0xab), w0(0x4d), w0(0x9a), w0(0x2f), + w0(0x5e), w0(0xbc), w0(0x63), w0(0xc6), + w0(0x97), w0(0x35), w0(0x6a), w0(0xd4), + w0(0xb3), w0(0x7d), w0(0xfa), w0(0xef), + w0(0xc5) +}; + +#ifdef SBX_SET +static const aes_08t s_box[256] = { sb_data(h0) }; +#endif +#ifdef ISB_SET +static const aes_08t inv_s_box[256] = { isb_data(h0) }; +#endif + +#ifdef FT1_SET +static const aes_32t ft_tab[256] = { sb_data(u0) }; +#endif +#ifdef FT4_SET +static const aes_32t ft_tab[4][256] = + { { sb_data(u0) }, { sb_data(u1) }, { sb_data(u2) }, { sb_data(u3) } }; +#endif + +#ifdef FL1_SET +static const aes_32t fl_tab[256] = { sb_data(w0) }; +#endif +#ifdef FL4_SET +static const aes_32t fl_tab[4][256] = + { { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } }; +#endif + +#ifdef IT1_SET +static const aes_32t it_tab[256] = { isb_data(v0) }; +#endif +#ifdef IT4_SET +static const aes_32t it_tab[4][256] = + { { isb_data(v0) }, { isb_data(v1) }, { isb_data(v2) }, { isb_data(v3) } }; +#endif + +#ifdef IL1_SET +static const aes_32t il_tab[256] = { isb_data(w0) }; +#endif +#ifdef IL4_SET +static const aes_32t il_tab[4][256] = + { { isb_data(w0) }, { isb_data(w1) }, { isb_data(w2) }, { isb_data(w3) } }; +#endif + +#ifdef LS1_SET +static const aes_32t ls_tab[256] = { sb_data(w0) }; +#endif +#ifdef LS4_SET +static const aes_32t ls_tab[4][256] = + { { sb_data(w0) }, { sb_data(w1) }, { sb_data(w2) }, { sb_data(w3) } }; +#endif + +#ifdef IM1_SET +static const aes_32t im_tab[256] = { mm_data(v0) }; +#endif +#ifdef IM4_SET +static const aes_32t im_tab[4][256] = + { { mm_data(v0) }, { mm_data(v1) }, { mm_data(v2) }, { mm_data(v3) } }; +#endif + +#else /* dynamic table generation */ + +aes_08t tab_init = 0; + +#define const + +static aes_32t rcon_tab[RC_LENGTH]; + +#ifdef SBX_SET +aes_08t s_box[256]; +#endif +#ifdef ISB_SET +aes_08t inv_s_box[256]; +#endif + +#ifdef FT1_SET +aes_32t ft_tab[256]; +#endif +#ifdef FT4_SET +aes_32t ft_tab[4][256]; +#endif + +#ifdef FL1_SET +aes_32t fl_tab[256]; +#endif +#ifdef FL4_SET +aes_32t fl_tab[4][256]; +#endif + +#ifdef IT1_SET +aes_32t it_tab[256]; +#endif +#ifdef IT4_SET +aes_32t it_tab[4][256]; +#endif + +#ifdef IL1_SET +aes_32t il_tab[256]; +#endif +#ifdef IL4_SET +aes_32t il_tab[4][256]; +#endif + +#ifdef LS1_SET +aes_32t ls_tab[256]; +#endif +#ifdef LS4_SET +aes_32t ls_tab[4][256]; +#endif + +#ifdef IM1_SET +aes_32t im_tab[256]; +#endif +#ifdef IM4_SET +aes_32t im_tab[4][256]; +#endif + +#if !defined(FF_TABLES) + +/* Generate the tables for the dynamic table option + + It will generally be sensible to use tables to compute finite + field multiplies and inverses but where memory is scarse this + code might sometimes be better. But it only has effect during + initialisation so its pretty unimportant in overall terms. +*/ + +/* return 2 ^ (n - 1) where n is the bit number of the highest bit + set in x with x in the range 1 < x < 0x00000200. This form is + used so that locals within fi can be bytes rather than words +*/ + +static aes_08t hibit(const aes_32t x) +{ aes_08t r = (aes_08t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static aes_08t fi(const aes_08t x) +{ aes_08t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) return x; + + for(;;) + { + if(!n1) return v1; + + while(n2 >= n1) + { + n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); + } + + if(!n2) return v2; + + while(n1 >= n2) + { + n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); + } + } +} + +#else + +/* define the finite field multiplies required for Rijndael */ + +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) +#define fi(x) ((x) ? pow[255 - log[x]]: 0) + +#endif + +/* The forward and inverse affine transformations used in the S-box */ + +#define fwd_affine(x) \ + (w = (aes_32t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(aes_08t)(w^(w>>8))) + +#define inv_affine(x) \ + (w = (aes_32t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(aes_08t)(w^(w>>8))) + +void gen_tabs(void) +{ aes_32t i, w; + +#if defined(FF_TABLES) + + aes_08t pow[512], log[256]; + + /* log and power tables for GF(2^8) finite field with + WPOLY as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables + */ + + i = 0; w = 1; + do + { + pow[i] = (aes_08t)w; + pow[i + 255] = (aes_08t)w; + log[w] = (aes_08t)i++; + w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); + } + while (w != 1); + +#endif + + for(i = 0, w = 1; i < RC_LENGTH; ++i) + { + rcon_tab[i] = bytes2word(w, 0, 0, 0); + w = f2(w); + } + + for(i = 0; i < 256; ++i) + { aes_08t b; + + b = fwd_affine(fi((aes_08t)i)); + w = bytes2word(f2(b), b, b, f3(b)); + +#ifdef SBX_SET + s_box[i] = b; +#endif + +#ifdef FT1_SET /* tables for a normal encryption round */ + ft_tab[i] = w; +#endif +#ifdef FT4_SET + ft_tab[0][i] = w; + ft_tab[1][i] = upr(w,1); + ft_tab[2][i] = upr(w,2); + ft_tab[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); + +#ifdef FL1_SET /* tables for last encryption round (may also */ + fl_tab[i] = w; /* be used in the key schedule) */ +#endif +#ifdef FL4_SET + fl_tab[0][i] = w; + fl_tab[1][i] = upr(w,1); + fl_tab[2][i] = upr(w,2); + fl_tab[3][i] = upr(w,3); +#endif + +#ifdef LS1_SET /* table for key schedule if fl_tab above is */ + ls_tab[i] = w; /* not of the required form */ +#endif +#ifdef LS4_SET + ls_tab[0][i] = w; + ls_tab[1][i] = upr(w,1); + ls_tab[2][i] = upr(w,2); + ls_tab[3][i] = upr(w,3); +#endif + + b = fi(inv_affine((aes_08t)i)); + w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + +#ifdef IM1_SET /* tables for the inverse mix column operation */ + im_tab[b] = w; +#endif +#ifdef IM4_SET + im_tab[0][b] = w; + im_tab[1][b] = upr(w,1); + im_tab[2][b] = upr(w,2); + im_tab[3][b] = upr(w,3); +#endif + +#ifdef ISB_SET + inv_s_box[i] = b; +#endif +#ifdef IT1_SET /* tables for a normal decryption round */ + it_tab[i] = w; +#endif +#ifdef IT4_SET + it_tab[0][i] = w; + it_tab[1][i] = upr(w,1); + it_tab[2][i] = upr(w,2); + it_tab[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); +#ifdef IL1_SET /* tables for last decryption round */ + il_tab[i] = w; +#endif +#ifdef IL4_SET + il_tab[0][i] = w; + il_tab[1][i] = upr(w,1); + il_tab[2][i] = upr(w,2); + il_tab[3][i] = upr(w,3); +#endif + } + + tab_init = 1; +} + +#endif + +/*---------------------------------------------------------------------- +| key schedule ++---------------------------------------------------------------------*/ +#if !defined(BLOCK_SIZE) + +static aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]) +{ +#if !defined(FIXED_TABLES) + if(!tab_init) gen_tabs(); +#endif + + if((blen & 7) || blen < 16 || blen > 32) + { + cx->n_blk = 0; return aes_bad; + } + + cx->n_blk = blen; + return aes_good; +} + +#endif + +/* Initialise the key schedule from the user supplied key. The key + length is now specified in bytes - 16, 24 or 32 as appropriate. + This corresponds to bit lengths of 128, 192 and 256 bits, and + to Nk values of 4, 6 and 8 respectively. + + The following macros implement a single cycle in the key + schedule generation process. The number of cycles needed + for each cx->n_col and nk value is: + + nk = 4 5 6 7 8 + ------------------------------ + cx->n_col = 4 10 9 8 7 7 + cx->n_col = 5 14 11 10 9 9 + cx->n_col = 6 19 15 12 11 11 + cx->n_col = 7 21 19 16 13 14 + cx->n_col = 8 29 23 19 17 14 +*/ + +#define ke4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ +} +#define kel4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ +} + +#define ke6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ + k[6*(i)+10] = ss[4] ^= ss[3]; k[6*(i)+11] = ss[5] ^= ss[4]; \ +} +#define kel6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ +} + +#define ke8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ + k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); k[8*(i)+13] = ss[5] ^= ss[4]; \ + k[8*(i)+14] = ss[6] ^= ss[5]; k[8*(i)+15] = ss[7] ^= ss[6]; \ +} +#define kel8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ +} + +#if defined(ENCRYPTION_KEY_SCHEDULE) + +static aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]) +{ aes_32t ss[8]; + +#if !defined(FIXED_TABLES) + if(!tab_init) gen_tabs(); +#endif + +#if !defined(BLOCK_SIZE) + if(!cx->n_blk) cx->n_blk = 16; +#else + cx->n_blk = BLOCK_SIZE; +#endif + + cx->n_blk = (cx->n_blk & ~3) | 1; + + cx->k_sch[0] = ss[0] = word_in(in_key ); + cx->k_sch[1] = ss[1] = word_in(in_key + 4); + cx->k_sch[2] = ss[2] = word_in(in_key + 8); + cx->k_sch[3] = ss[3] = word_in(in_key + 12); + +#if (BLOCK_SIZE == 16) && (ENC_UNROLL != NONE) + + switch(klen) + { + case 16: ke4(cx->k_sch, 0); ke4(cx->k_sch, 1); + ke4(cx->k_sch, 2); ke4(cx->k_sch, 3); + ke4(cx->k_sch, 4); ke4(cx->k_sch, 5); + ke4(cx->k_sch, 6); ke4(cx->k_sch, 7); + ke4(cx->k_sch, 8); kel4(cx->k_sch, 9); + cx->n_rnd = 10; break; + case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + ke6(cx->k_sch, 0); ke6(cx->k_sch, 1); + ke6(cx->k_sch, 2); ke6(cx->k_sch, 3); + ke6(cx->k_sch, 4); ke6(cx->k_sch, 5); + ke6(cx->k_sch, 6); kel6(cx->k_sch, 7); + cx->n_rnd = 12; break; + case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + cx->k_sch[6] = ss[6] = word_in(in_key + 24); + cx->k_sch[7] = ss[7] = word_in(in_key + 28); + ke8(cx->k_sch, 0); ke8(cx->k_sch, 1); + ke8(cx->k_sch, 2); ke8(cx->k_sch, 3); + ke8(cx->k_sch, 4); ke8(cx->k_sch, 5); + kel8(cx->k_sch, 6); + cx->n_rnd = 14; break; + default: cx->n_rnd = 0; return aes_bad; + } +#else + { aes_32t i, l; + cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6; + l = (nc * cx->n_rnd + nc - 1) / (klen >> 2); + + switch(klen) + { + case 16: for(i = 0; i < l; ++i) + ke4(cx->k_sch, i); + break; + case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + for(i = 0; i < l; ++i) + ke6(cx->k_sch, i); + break; + case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + cx->k_sch[6] = ss[6] = word_in(in_key + 24); + cx->k_sch[7] = ss[7] = word_in(in_key + 28); + for(i = 0; i < l; ++i) + ke8(cx->k_sch, i); + break; + default: cx->n_rnd = 0; return aes_bad; + } + } +#endif + + return aes_good; +} + +#endif + +#if defined(DECRYPTION_KEY_SCHEDULE) + +#if (DEC_ROUND != NO_TABLES) +#define d_vars dec_imvars +#define ff(x) inv_mcol(x) +#else +#define ff(x) (x) +#define d_vars +#endif + +#if 1 +#define kdf4(k,i) \ +{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; ss[1] = ss[1] ^ ss[3]; ss[2] = ss[2] ^ ss[3]; ss[3] = ss[3]; \ + ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[4*(i)]; k[4*(i)+4] = ff(ss[4]); ss[4] ^= k[4*(i)+1]; k[4*(i)+5] = ff(ss[4]); \ + ss[4] ^= k[4*(i)+2]; k[4*(i)+6] = ff(ss[4]); ss[4] ^= k[4*(i)+3]; k[4*(i)+7] = ff(ss[4]); \ +} +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ + k[4*(i)+4] = ss[4] ^= k[4*(i)]; k[4*(i)+5] = ss[4] ^= k[4*(i)+1]; \ + k[4*(i)+6] = ss[4] ^= k[4*(i)+2]; k[4*(i)+7] = ss[4] ^= k[4*(i)+3]; \ +} +#define kdl4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \ + k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; k[4*(i)+5] = ss[1] ^ ss[3]; \ + k[4*(i)+6] = ss[0]; k[4*(i)+7] = ss[1]; \ +} +#else +#define kdf4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ff(ss[0]); ss[1] ^= ss[0]; k[4*(i)+ 5] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ff(ss[2]); ss[3] ^= ss[2]; k[4*(i)+ 7] = ff(ss[3]); \ +} +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[3],3) ^ rcon_tab[i]; \ + ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[4*(i)+ 4] = ss[4] ^= k[4*(i)]; \ + ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[4] ^= k[4*(i)+ 1]; \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[4] ^= k[4*(i)+ 2]; \ + ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[4] ^= k[4*(i)+ 3]; \ +} +#define kdl4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ss[0]; ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[1]; \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[2]; ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[3]; \ +} +#endif + +#define kdf6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ff(ss[0]); ss[1] ^= ss[0]; k[6*(i)+ 7] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ff(ss[2]); ss[3] ^= ss[2]; k[6*(i)+ 9] = ff(ss[3]); \ + ss[4] ^= ss[3]; k[6*(i)+10] = ff(ss[4]); ss[5] ^= ss[4]; k[6*(i)+11] = ff(ss[5]); \ +} +#define kd6(k,i) \ +{ ss[6] = ls_box(ss[5],3) ^ rcon_tab[i]; \ + ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[6*(i)+ 6] = ss[6] ^= k[6*(i)]; \ + ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1]; \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2]; \ + ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3]; \ + ss[4] ^= ss[3]; k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4]; \ + ss[5] ^= ss[4]; k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5]; \ +} +#define kdl6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ss[0]; ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[1]; \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[2]; ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[3]; \ +} + +#define kdf8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ff(ss[0]); ss[1] ^= ss[0]; k[8*(i)+ 9] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[8*(i)+10] = ff(ss[2]); ss[3] ^= ss[2]; k[8*(i)+11] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3],0); k[8*(i)+12] = ff(ss[4]); ss[5] ^= ss[4]; k[8*(i)+13] = ff(ss[5]); \ + ss[6] ^= ss[5]; k[8*(i)+14] = ff(ss[6]); ss[7] ^= ss[6]; k[8*(i)+15] = ff(ss[7]); \ +} +#define kd8(k,i) \ +{ aes_32t g = ls_box(ss[7],3) ^ rcon_tab[i]; \ + ss[0] ^= g; g = ff(g); k[8*(i)+ 8] = g ^= k[8*(i)]; \ + ss[1] ^= ss[0]; k[8*(i)+ 9] = g ^= k[8*(i)+ 1]; \ + ss[2] ^= ss[1]; k[8*(i)+10] = g ^= k[8*(i)+ 2]; \ + ss[3] ^= ss[2]; k[8*(i)+11] = g ^= k[8*(i)+ 3]; \ + g = ls_box(ss[3],0); \ + ss[4] ^= g; g = ff(g); k[8*(i)+12] = g ^= k[8*(i)+ 4]; \ + ss[5] ^= ss[4]; k[8*(i)+13] = g ^= k[8*(i)+ 5]; \ + ss[6] ^= ss[5]; k[8*(i)+14] = g ^= k[8*(i)+ 6]; \ + ss[7] ^= ss[6]; k[8*(i)+15] = g ^= k[8*(i)+ 7]; \ +} +#define kdl8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ss[0]; ss[1] ^= ss[0]; k[8*(i)+ 9] = ss[1]; \ + ss[2] ^= ss[1]; k[8*(i)+10] = ss[2]; ss[3] ^= ss[2]; k[8*(i)+11] = ss[3]; \ +} + +static aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]) +{ aes_32t ss[8]; + d_vars + +#if !defined(FIXED_TABLES) + if(!tab_init) gen_tabs(); +#endif + +#if !defined(BLOCK_SIZE) + if(!cx->n_blk) cx->n_blk = 16; +#else + cx->n_blk = BLOCK_SIZE; +#endif + + cx->n_blk = (cx->n_blk & ~3) | 2; + + cx->k_sch[0] = ss[0] = word_in(in_key ); + cx->k_sch[1] = ss[1] = word_in(in_key + 4); + cx->k_sch[2] = ss[2] = word_in(in_key + 8); + cx->k_sch[3] = ss[3] = word_in(in_key + 12); + +#if (BLOCK_SIZE == 16) && (DEC_UNROLL != NONE) + + switch(klen) + { + case 16: kdf4(cx->k_sch, 0); kd4(cx->k_sch, 1); + kd4(cx->k_sch, 2); kd4(cx->k_sch, 3); + kd4(cx->k_sch, 4); kd4(cx->k_sch, 5); + kd4(cx->k_sch, 6); kd4(cx->k_sch, 7); + kd4(cx->k_sch, 8); kdl4(cx->k_sch, 9); + cx->n_rnd = 10; break; + case 24: cx->k_sch[4] = ff(ss[4] = word_in(in_key + 16)); + cx->k_sch[5] = ff(ss[5] = word_in(in_key + 20)); + kdf6(cx->k_sch, 0); kd6(cx->k_sch, 1); + kd6(cx->k_sch, 2); kd6(cx->k_sch, 3); + kd6(cx->k_sch, 4); kd6(cx->k_sch, 5); + kd6(cx->k_sch, 6); kdl6(cx->k_sch, 7); + cx->n_rnd = 12; break; + case 32: cx->k_sch[4] = ff(ss[4] = word_in(in_key + 16)); + cx->k_sch[5] = ff(ss[5] = word_in(in_key + 20)); + cx->k_sch[6] = ff(ss[6] = word_in(in_key + 24)); + cx->k_sch[7] = ff(ss[7] = word_in(in_key + 28)); + kdf8(cx->k_sch, 0); kd8(cx->k_sch, 1); + kd8(cx->k_sch, 2); kd8(cx->k_sch, 3); + kd8(cx->k_sch, 4); kd8(cx->k_sch, 5); + kdl8(cx->k_sch, 6); + cx->n_rnd = 14; break; + default: cx->n_rnd = 0; return aes_bad; + } +#else + { aes_32t i, l; + cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6; + l = (nc * cx->n_rnd + nc - 1) / (klen >> 2); + + switch(klen) + { + case 16: + for(i = 0; i < l; ++i) + ke4(cx->k_sch, i); + break; + case 24: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + for(i = 0; i < l; ++i) + ke6(cx->k_sch, i); + break; + case 32: cx->k_sch[4] = ss[4] = word_in(in_key + 16); + cx->k_sch[5] = ss[5] = word_in(in_key + 20); + cx->k_sch[6] = ss[6] = word_in(in_key + 24); + cx->k_sch[7] = ss[7] = word_in(in_key + 28); + for(i = 0; i < l; ++i) + ke8(cx->k_sch, i); + break; + default: cx->n_rnd = 0; return aes_bad; + } +#if (DEC_ROUND != NO_TABLES) + for(i = nc; i < nc * cx->n_rnd; ++i) + cx->k_sch[i] = inv_mcol(cx->k_sch[i]); +#endif + } +#endif + + return aes_good; +} + +#endif + +/*---------------------------------------------------------------------- +| cipher ++---------------------------------------------------------------------*/ +#define unused 77 /* Sunset Strip */ + +#define si(y,x,k,c) s(y,c) = word_in(x + 4 * c) ^ k[c] +#define so(y,x,c) word_out(y + 4 * c, s(x,c)) + +#if BLOCK_SIZE == 16 + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 + /* + the following defines prevent the compiler requiring the declaration + of generated but unused variables in the fwd_var and inv_var macros + */ +#define b04 unused +#define b05 unused +#define b06 unused +#define b07 unused +#define b14 unused +#define b15 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#elif BLOCK_SIZE == 24 + +#if defined(ARRAYS) +#define locals(y,x) x[6],y[6] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \ + y##0,y##1,y##2,y##3,y##4,y##5 +#define b06 unused +#define b07 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \ + si(y,x,k,3); si(y,x,k,4); si(y,x,k,5) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \ + so(y,x,3); so(y,x,4); so(y,x,5) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \ + rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5) +#else + +#if defined(ARRAYS) +#define locals(y,x) x[8],y[8] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \ + y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7 +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); \ + s(y,6) = s(x,6); s(y,7) = s(x,7); + +#if BLOCK_SIZE == 32 + +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \ + si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \ + so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \ + rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7) +#else + +#define state_in(y,x,k) \ +switch(nc) \ +{ case 8: si(y,x,k,7); si(y,x,k,6); \ + case 6: si(y,x,k,5); si(y,x,k,4); \ + case 4: si(y,x,k,3); si(y,x,k,2); \ + si(y,x,k,1); si(y,x,k,0); \ +} + +#define state_out(y,x) \ +switch(nc) \ +{ case 8: so(y,x,7); so(y,x,6); \ + case 6: so(y,x,5); so(y,x,4); \ + case 4: so(y,x,3); so(y,x,2); \ + so(y,x,1); so(y,x,0); \ +} + +#if defined(FAST_VARIABLE) + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ +} +#else + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ +} + +#endif + +#endif +#endif + +#if defined(ENCRYPTION) + +/* I am grateful to Frank Yellin for the following construction + (and that for decryption) which, given the column (c) of the + output state variable, gives the input state variables which + are needed in its computation for each row (r) of the state. + + For the fixed block size options, compilers should be able to + reduce this complex expression (and the equivalent one for + decryption) to a static variable reference at compile time. + But for variable block size code, there will be some limbs on + which conditional clauses will be returned. +*/ + +/* y = output word, x = input word, r = row, c = column for r = 0, + 1, 2 and 3 = column accessed for row r. +*/ + +#define fwd_var(x,r,c)\ + ( r == 0 ? \ + ( c == 0 ? s(x,0) \ + : c == 1 ? s(x,1) \ + : c == 2 ? s(x,2) \ + : c == 3 ? s(x,3) \ + : c == 4 ? s(x,4) \ + : c == 5 ? s(x,5) \ + : c == 6 ? s(x,6) \ + : s(x,7))\ + : r == 1 ? \ + ( c == 0 ? s(x,1) \ + : c == 1 ? s(x,2) \ + : c == 2 ? s(x,3) \ + : c == 3 ? nc == 4 ? s(x,0) : s(x,4) \ + : c == 4 ? s(x,5) \ + : c == 5 ? nc == 8 ? s(x,6) : s(x,0) \ + : c == 6 ? s(x,7) \ + : s(x,0))\ + : r == 2 ? \ + ( c == 0 ? nc == 8 ? s(x,3) : s(x,2) \ + : c == 1 ? nc == 8 ? s(x,4) : s(x,3) \ + : c == 2 ? nc == 4 ? s(x,0) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 3 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 4 ? nc == 8 ? s(x,7) : s(x,0) \ + : c == 5 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 6 ? s(x,1) \ + : s(x,2))\ + : \ + ( c == 0 ? nc == 8 ? s(x,4) : s(x,3) \ + : c == 1 ? nc == 4 ? s(x,0) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 2 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 3 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,7) : s(x,0) \ + : c == 4 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 5 ? nc == 8 ? s(x,1) : s(x,2) \ + : c == 6 ? s(x,2) \ + : s(x,3))) + +#if defined(FT4_SET) +#undef dec_fmvars +#define dec_fmvars +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c) +#elif defined(FT1_SET) +#undef dec_fmvars +#define dec_fmvars +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c) +#else +#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c] +#endif + +#if defined(FL4_SET) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c) +#elif defined(FL1_SET) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c) +#else +#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c] +#endif + +static aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]) +{ aes_32t locals(b0, b1); + const aes_32t *kp = cx->k_sch; + dec_fmvars /* declare variables for fwd_mcol() if needed */ + + if(!(cx->n_blk & 1)) return aes_bad; + + state_in(b0, in_blk, kp); + +#if (ENC_UNROLL == FULL) + + kp += (cx->n_rnd - 9) * nc; + + switch(cx->n_rnd) + { + case 14: round(fwd_rnd, b1, b0, kp - 4 * nc); + round(fwd_rnd, b0, b1, kp - 3 * nc); + case 12: round(fwd_rnd, b1, b0, kp - 2 * nc); + round(fwd_rnd, b0, b1, kp - nc); + case 10: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc); + round(fwd_rnd, b1, b0, kp + 2 * nc); + round(fwd_rnd, b0, b1, kp + 3 * nc); + round(fwd_rnd, b1, b0, kp + 4 * nc); + round(fwd_rnd, b0, b1, kp + 5 * nc); + round(fwd_rnd, b1, b0, kp + 6 * nc); + round(fwd_rnd, b0, b1, kp + 7 * nc); + round(fwd_rnd, b1, b0, kp + 8 * nc); + round(fwd_lrnd, b0, b1, kp + 9 * nc); + } +#else + +#if (ENC_UNROLL == PARTIAL) + { aes_32t rnd; + for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd) + { + kp += nc; + round(fwd_rnd, b1, b0, kp); + kp += nc; + round(fwd_rnd, b0, b1, kp); + } + kp += nc; + round(fwd_rnd, b1, b0, kp); +#else + { aes_32t rnd, *p0 = b0, *p1 = b1, *pt; + for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd) + { + kp += nc; + round(fwd_rnd, p1, p0, kp); + pt = p0, p0 = p1, p1 = pt; + } +#endif + kp += nc; + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); + return aes_good; +} + +#endif + +#if defined(DECRYPTION) + +#define inv_var(x,r,c) \ + ( r == 0 ? \ + ( c == 0 ? s(x,0) \ + : c == 1 ? s(x,1) \ + : c == 2 ? s(x,2) \ + : c == 3 ? s(x,3) \ + : c == 4 ? s(x,4) \ + : c == 5 ? s(x,5) \ + : c == 6 ? s(x,6) \ + : s(x,7))\ + : r == 1 ? \ + ( c == 0 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,7) : s(x,5) \ + : c == 1 ? s(x,0) \ + : c == 2 ? s(x,1) \ + : c == 3 ? s(x,2) \ + : c == 4 ? s(x,3) \ + : c == 5 ? s(x,4) \ + : c == 6 ? s(x,5) \ + : s(x,6))\ + : r == 2 ? \ + ( c == 0 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 1 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 2 ? nc == 8 ? s(x,7) : s(x,0) \ + : c == 3 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 4 ? nc == 8 ? s(x,1) : s(x,2) \ + : c == 5 ? nc == 8 ? s(x,2) : s(x,3) \ + : c == 6 ? s(x,3) \ + : s(x,4))\ + : \ + ( c == 0 ? nc == 4 ? s(x,1) : nc == 8 ? s(x,4) : s(x,3) \ + : c == 1 ? nc == 4 ? s(x,2) : nc == 8 ? s(x,5) : s(x,4) \ + : c == 2 ? nc == 4 ? s(x,3) : nc == 8 ? s(x,6) : s(x,5) \ + : c == 3 ? nc == 8 ? s(x,7) : s(x,0) \ + : c == 4 ? nc == 8 ? s(x,0) : s(x,1) \ + : c == 5 ? nc == 8 ? s(x,1) : s(x,2) \ + : c == 6 ? s(x,2) \ + : s(x,3))) + +#if defined(IT4_SET) +#undef dec_imvars +#define dec_imvars +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c) +#elif defined(IT1_SET) +#undef dec_imvars +#define dec_imvars +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c) +#else +#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]) +#endif + +#if defined(IL4_SET) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c) +#elif defined(IL1_SET) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c) +#else +#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c] +#endif + +static aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]) +{ aes_32t locals(b0, b1); + const aes_32t *kp = cx->k_sch + nc * cx->n_rnd; + dec_imvars /* declare variables for inv_mcol() if needed */ + + if(!(cx->n_blk & 2)) return aes_bad; + + state_in(b0, in_blk, kp); + +#if (DEC_UNROLL == FULL) + + kp = cx->k_sch + 9 * nc; + switch(cx->n_rnd) + { + case 14: round(inv_rnd, b1, b0, kp + 4 * nc); + round(inv_rnd, b0, b1, kp + 3 * nc); + case 12: round(inv_rnd, b1, b0, kp + 2 * nc); + round(inv_rnd, b0, b1, kp + nc ); + case 10: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp - nc); + round(inv_rnd, b1, b0, kp - 2 * nc); + round(inv_rnd, b0, b1, kp - 3 * nc); + round(inv_rnd, b1, b0, kp - 4 * nc); + round(inv_rnd, b0, b1, kp - 5 * nc); + round(inv_rnd, b1, b0, kp - 6 * nc); + round(inv_rnd, b0, b1, kp - 7 * nc); + round(inv_rnd, b1, b0, kp - 8 * nc); + round(inv_lrnd, b0, b1, kp - 9 * nc); + } +#else + +#if (DEC_UNROLL == PARTIAL) + { aes_32t rnd; + for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd) + { + kp -= nc; + round(inv_rnd, b1, b0, kp); + kp -= nc; + round(inv_rnd, b0, b1, kp); + } + kp -= nc; + round(inv_rnd, b1, b0, kp); +#else + { aes_32t rnd, *p0 = b0, *p1 = b1, *pt; + for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd) + { + kp -= nc; + round(inv_rnd, p1, p0, kp); + pt = p0, p0 = p1, p1 = pt; + } +#endif + kp -= nc; + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); + return aes_good; +} + +#endif + +/*---------------------------------------------------------------------- +| AP4_AesBlockCipher::AP4_AesBlockCipher ++---------------------------------------------------------------------*/ +AP4_AesBlockCipher::AP4_AesBlockCipher(const AP4_UI08* key, + CipherDirection direction) : + m_Direction(direction) +{ + m_Context = new aes_ctx; + if (direction == AP4_BlockCipher::ENCRYPT) { + aes_enc_key(key, AP4_AES_KEY_LENGTH, m_Context); + } else { + aes_dec_key(key, AP4_AES_KEY_LENGTH, m_Context); + } +} + +/*---------------------------------------------------------------------- +| AP4_AesBlockCipher::~AP4_AesBlockCipher ++---------------------------------------------------------------------*/ +AP4_AesBlockCipher::~AP4_AesBlockCipher() +{ + delete m_Context; +} + +/*---------------------------------------------------------------------- +| AP4_AesBlockCipher::EncryptBlock ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AesBlockCipher::ProcessBlock(const AP4_UI08* block_in, + AP4_UI08* block_out) +{ + aes_rval result; + if (m_Direction == AP4_BlockCipher::ENCRYPT) { + result = aes_enc_blk(block_in, block_out, m_Context); + } else { + result = aes_dec_blk(block_in, block_out, m_Context); + } + return result == aes_good ? AP4_SUCCESS : AP4_FAILURE; +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4AesBlockCipher.h b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4AesBlockCipher.h new file mode 100644 index 000000000..353cf6473 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4AesBlockCipher.h @@ -0,0 +1,78 @@ +/* + * AES Block cipher + * (c) 2005-2008 Axiomatic Systems, LLC + * Portions (c) 2001, Dr Brian Gladman (see below) + */ + +/* + ------------------------------------------------------------------------- + Copyright (c) 2001, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and fitness for purpose. + ------------------------------------------------------------------------- + Issue Date: 29/07/2002 +*/ + +#ifndef _AP4_AES_BLOCK_CIPHER_H_ +#define _AP4_AES_BLOCK_CIPHER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Types.h" +#include "Ap4Config.h" +#include "Ap4Protection.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +struct aes_ctx; + +/*---------------------------------------------------------------------- +| AES constants ++---------------------------------------------------------------------*/ +#define AP4_AES_BLOCK_SIZE 16 +#define AP4_AES_KEY_LENGTH 16 + +/*---------------------------------------------------------------------- +| AP4_AesBlockCipher class ++---------------------------------------------------------------------*/ +class AP4_AesBlockCipher : public AP4_BlockCipher +{ +public: + // constructor and destructor + AP4_AesBlockCipher(const AP4_UI08* key, + AP4_BlockCipher::CipherDirection direction); + ~AP4_AesBlockCipher(); + + // AP4_AesBlockCipher methods + virtual AP4_Result ProcessBlock(const AP4_UI08* input, + AP4_UI08* output); + +private: + // members + CipherDirection m_Direction; + aes_ctx* m_Context; +}; + +#endif // _AP4_AES_BLOCK_CIPHER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4Hmac.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4Hmac.cpp new file mode 100644 index 000000000..387f69453 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4Hmac.cpp @@ -0,0 +1,330 @@ +/***************************************************************** +| +| AP4 - HMAC Algorithms +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/* + Portions of this code are based on the code of LibTomCrypt + that was released into public domain by Tom St Denis. +*/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Hmac.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define AP4_SHA256_BLOCK_SIZE 64 + +static const AP4_UI32 AP4_Sha256_K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/*---------------------------------------------------------------------- +| AP4_DigestSha256 ++---------------------------------------------------------------------*/ +class AP4_DigestSha256 +{ +public: + AP4_DigestSha256(); + virtual ~AP4_DigestSha256() {} + + // AP4_Hmac methods + virtual AP4_Result Update(const AP4_UI08* data, AP4_Size data_size); + virtual AP4_Result Final(AP4_DataBuffer& digest); + +private: + // methods + void CompressBlock(const AP4_UI08* block); + + // members + AP4_UI64 m_Length; + AP4_UI32 m_Pending; + AP4_UI32 m_State[8]; + AP4_UI08 m_Buffer[64]; +}; + +/*---------------------------------------------------------------------- +| AP4_HmacSha256 +| +| compute SHA256(key XOR opad, SHA256(key XOR ipad, data)) +| key is the MAC key +| ipad is the byte 0x36 repeated 64 times +| opad is the byte 0x5c repeated 64 times +| and data is the data to authenticate +| ++---------------------------------------------------------------------*/ +class AP4_HmacSha256 : public AP4_Hmac +{ +public: + AP4_HmacSha256(const AP4_UI08* key, AP4_Size key_size); + + // AP4_Hmac methods + virtual AP4_Result Update(const AP4_UI08* data, AP4_Size data_size) { + return m_InnerDigest.Update(data, data_size); + } + virtual AP4_Result Final(AP4_DataBuffer& buffer); + +private: + AP4_DigestSha256 m_InnerDigest; + AP4_DigestSha256 m_OuterDigest; +}; + +/*---------------------------------------------------------------------- +| AP4_DigestSha256::AP4_DigestSha256 ++---------------------------------------------------------------------*/ +AP4_DigestSha256::AP4_DigestSha256() : + m_Length(0), + m_Pending(0) +{ + m_State[0] = 0x6A09E667UL; + m_State[1] = 0xBB67AE85UL; + m_State[2] = 0x3C6EF372UL; + m_State[3] = 0xA54FF53AUL; + m_State[4] = 0x510E527FUL; + m_State[5] = 0x9B05688CUL; + m_State[6] = 0x1F83D9ABUL; + m_State[7] = 0x5BE0CD19UL; +} + +/*---------------------------------------------------------------------- +| local macros ++---------------------------------------------------------------------*/ +#define AP4_Sha256_RORc(x, y) \ +( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ + ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define AP4_Sha256_Ch(x,y,z) (z ^ (x & (y ^ z))) +#define AP4_Sha256_Maj(x,y,z) (((x | y) & z) | (x & y)) +#define AP4_Sha256_S(x, n) AP4_Sha256_RORc((x), (n)) +#define AP4_Sha256_R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define AP4_Sha256_Sigma0(x) (AP4_Sha256_S(x, 2) ^ AP4_Sha256_S(x, 13) ^ AP4_Sha256_S(x, 22)) +#define AP4_Sha256_Sigma1(x) (AP4_Sha256_S(x, 6) ^ AP4_Sha256_S(x, 11) ^ AP4_Sha256_S(x, 25)) +#define AP4_Sha256_Gamma0(x) (AP4_Sha256_S(x, 7) ^ AP4_Sha256_S(x, 18) ^ AP4_Sha256_R(x, 3)) +#define AP4_Sha256_Gamma1(x) (AP4_Sha256_S(x, 17) ^ AP4_Sha256_S(x, 19) ^ AP4_Sha256_R(x, 10)) + +/*---------------------------------------------------------------------- +| AP4_DigestSha256::CompressBlock ++---------------------------------------------------------------------*/ +void +AP4_DigestSha256::CompressBlock(const AP4_UI08* block) +{ + AP4_UI32 S[8], W[64]; + + /* copy the state into S */ + for (unsigned int i = 0; i < 8; i++) { + S[i] = m_State[i]; + } + + /* copy the 512-bit block into W[0..15] */ + for (unsigned int i = 0; i < 16; i++) { + W[i] = AP4_BytesToUInt32BE(&block[4*i]); + } + + /* fill W[16..63] */ + for (unsigned int i = 16; i < AP4_SHA256_BLOCK_SIZE; i++) { + W[i] = AP4_Sha256_Gamma1(W[i-2]) + W[i-7] + AP4_Sha256_Gamma0(W[i-15]) + W[i-16]; + } + + /* compress */ + AP4_UI32 t, t0, t1; + for (unsigned int i = 0; i < AP4_SHA256_BLOCK_SIZE; ++i) { + t0 = S[7] + AP4_Sha256_Sigma1(S[4]) + AP4_Sha256_Ch(S[4], S[5], S[6]) + AP4_Sha256_K[i] + W[i]; + t1 = AP4_Sha256_Sigma0(S[0]) + AP4_Sha256_Maj(S[0], S[1], S[2]); + S[3] += t0; + S[7] = t0 + t1; + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* feedback */ + for (unsigned int i = 0; i < 8; i++) { + m_State[i] = m_State[i] + S[i]; + } +} + + +/*---------------------------------------------------------------------- +| AP4_DigestSha256::Update ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DigestSha256::Update(const AP4_UI08* data, AP4_Size data_size) +{ + while (data_size > 0) { + if (m_Pending == 0 && data_size >= AP4_SHA256_BLOCK_SIZE) { + CompressBlock(data); + m_Length += AP4_SHA256_BLOCK_SIZE * 8; + data += AP4_SHA256_BLOCK_SIZE; + data_size -= AP4_SHA256_BLOCK_SIZE; + } else { + unsigned int chunk = data_size; + if (chunk > (AP4_SHA256_BLOCK_SIZE - m_Pending)) { + chunk = AP4_SHA256_BLOCK_SIZE - m_Pending; + } + AP4_CopyMemory(&m_Buffer[m_Pending], data, chunk); + m_Pending += chunk; + data += chunk; + data_size -= chunk; + if (m_Pending == AP4_SHA256_BLOCK_SIZE) { + CompressBlock(m_Buffer); + m_Length += 8 * AP4_SHA256_BLOCK_SIZE; + m_Pending = 0; + } + } + } + + return AP4_SUCCESS; +} + + +/*---------------------------------------------------------------------- +| AP4_DigestSha256::Final ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DigestSha256::Final(AP4_DataBuffer& digest) +{ + /* increase the length of the message */ + m_Length += m_Pending * 8; + + /* append the '1' bit */ + m_Buffer[m_Pending++] = 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (m_Pending > 56) { + while (m_Pending < 64) { + m_Buffer[m_Pending++] = 0; + } + CompressBlock(m_Buffer); + m_Pending = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (m_Pending < 56) { + m_Buffer[m_Pending++] = 0; + } + + /* store length */ + AP4_BytesFromUInt64BE(&m_Buffer[56], m_Length); + CompressBlock(m_Buffer); + + /* copy output */ + digest.SetDataSize(32); + AP4_UI08* out = digest.UseData(); + for (unsigned int i = 0; i < 8; i++) { + AP4_BytesFromUInt32BE(out, m_State[i]); + out += 4; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HmacSha256::AP4_HmacSha256 ++---------------------------------------------------------------------*/ +AP4_HmacSha256::AP4_HmacSha256(const AP4_UI08* key, AP4_Size key_size) +{ + AP4_UI08 workspace[AP4_SHA256_BLOCK_SIZE]; + + /* if the key is larger than the block size, use a digest of the key */ + AP4_DataBuffer hk; + if (key_size > AP4_SHA256_BLOCK_SIZE) { + AP4_DigestSha256 kdigest; + kdigest.Update(key, key_size); + kdigest.Final(hk); + key = hk.GetData(); + key_size = hk.GetDataSize(); + } + + /* compute key XOR ipad */ + for (unsigned int i = 0; i < key_size; i++) { + workspace[i] = key[i] ^ 0x36; + } + for (unsigned int i = key_size; i < AP4_SHA256_BLOCK_SIZE; i++) { + workspace[i] = 0x36; + } + + /* start the inner digest with (key XOR ipad) */ + m_InnerDigest.Update(workspace, AP4_SHA256_BLOCK_SIZE); + + /* compute key XOR opad */ + for (unsigned int i = 0; i < key_size; i++) { + workspace[i] = key[i] ^ 0x5c; + } + for (unsigned int i = key_size; i < AP4_SHA256_BLOCK_SIZE; i++) { + workspace[i] = 0x5c; + } + + /* start the outer digest with (key XOR opad) */ + m_OuterDigest.Update(workspace, AP4_SHA256_BLOCK_SIZE); +} + +/*---------------------------------------------------------------------- +| AP4_HmacSha256::Final ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HmacSha256::Final(AP4_DataBuffer& mac) +{ + /* finish the outer digest with the value of the inner digest */ + AP4_DataBuffer inner; + m_InnerDigest.Final(inner); + m_OuterDigest.Update(inner.GetData(), inner.GetDataSize()); + + /* return the value of the outer digest */ + return m_OuterDigest.Final(mac); +} + +/*---------------------------------------------------------------------- +| AP4_Hmac::Create ++---------------------------------------------------------------------*/ +AP4_Result +AP4_Hmac::Create(Algorithm algorithm, + const AP4_UI08* key, + AP4_Size key_size, + AP4_Hmac*& hmac) +{ + switch (algorithm) { + case SHA256: hmac = new AP4_HmacSha256(key, key_size); return AP4_SUCCESS; + default: hmac = NULL; return AP4_ERROR_NOT_SUPPORTED; + } +} + diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4Hmac.h b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4Hmac.h new file mode 100644 index 000000000..22957a0d4 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4Hmac.h @@ -0,0 +1,62 @@ +/***************************************************************** +| +| AP4 - HMAC Algorithms +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_HMAC_H_ +#define _AP4_HMAC_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Results.h" +#include "Ap4Types.h" +#include "Ap4DataBuffer.h" + +/*---------------------------------------------------------------------- +| AP4_Hmac ++---------------------------------------------------------------------*/ +class AP4_Hmac +{ +public: + // types + typedef enum { + SHA256 + } Algorithm; + + // class methods + static AP4_Result Create(Algorithm algorithm, + const AP4_UI08* key, + AP4_Size key_size, + AP4_Hmac*& hmac); + + // methods + virtual ~AP4_Hmac() {} + virtual AP4_Result Update(const AP4_UI08* data, AP4_Size data_size) = 0; + virtual AP4_Result Final(AP4_DataBuffer& mac) = 0; +}; + +#endif // _AP4_HMAC_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4KeyWrap.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4KeyWrap.cpp new file mode 100644 index 000000000..3cc37f5ce --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4KeyWrap.cpp @@ -0,0 +1,167 @@ +/***************************************************************** +| +| AP4 - HMAC Algorithms +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/* + Portions of this code are based on the code of LibTomCrypt + that was released into public domain by Tom St Denis. +*/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4KeyWrap.h" +#include "Ap4AesBlockCipher.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- +| AP4_AesKeyWrap ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AesKeyWrap(const AP4_UI08* kek, + const AP4_UI08* cleartext_key, + AP4_Size cleartext_key_size, + AP4_DataBuffer& wrapped_key) +{ + // check parameters + if (cleartext_key_size % 8) { + // not a multiple of 64 bits + return AP4_ERROR_INVALID_PARAMETERS; + } + + // the output size is (n+1)*64 bits + // where n is the number of 64-bit blocks + // of the cleartext key + unsigned int n = cleartext_key_size/8; + wrapped_key.SetDataSize((n+1)*8); + + // Step 1. Initialize variables. + // Set A = IV, an initial value (0xA6) + // For i = 1 to n + // R[i] = P[i] + AP4_UI08* a = (AP4_UI08*)wrapped_key.UseData(); + AP4_SetMemory(a, 0xA6, 8); + AP4_UI08* r = a+8; + AP4_CopyMemory(r, cleartext_key, cleartext_key_size); + + // Step 2. Calculate intermediate values. + // For j = 0 to 5 + // For i=1 to n + // B = AES(K, A | R[i]) + // A = MSB(64, B) ^ t where t = (n*j)+i + // R[i] = LSB(64, B) + AP4_AesBlockCipher block_cipher(kek, AP4_BlockCipher::ENCRYPT); + for (unsigned int j=0; j <= 5; j++) { + r = a + 8; + for (unsigned int i=1; i<=n; i++) { + AP4_UI08 workspace[16]; + AP4_UI08 b[16]; + AP4_CopyMemory(workspace, a, 8); + AP4_CopyMemory(&workspace[8], r, 8); + block_cipher.ProcessBlock(workspace, b); + AP4_CopyMemory(a, b, 8); + a[7] ^= n*j+i; + AP4_CopyMemory(r, &b[8], 8); + r += 8; + } + } + + // Step 3. Output the results. + // (Nothing to do here since we've worked in-place + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_AesKeyUnwrap ++---------------------------------------------------------------------*/ +AP4_Result +AP4_AesKeyUnwrap(const AP4_UI08* kek, + const AP4_UI08* wrapped_key, + AP4_Size wrapped_key_size, + AP4_DataBuffer& cleartext_key) +{ + // check parameters + if ((wrapped_key_size % 8) || (wrapped_key_size < 24)) { + // not a multiple of 64 bits or too small + return AP4_ERROR_INVALID_PARAMETERS; + } + + // setup the output buffer + unsigned int n = (wrapped_key_size/8)-1; + cleartext_key.SetDataSize(n*8); + + // Step 1. Initialize variables. + // Set A = C[0] + // For i = 1 to n + // R[i] = C[i] + AP4_UI08 a[8]; + AP4_CopyMemory(a, wrapped_key, 8); + AP4_UI08* r = (AP4_UI08*)cleartext_key.UseData(); + AP4_CopyMemory(r, wrapped_key+8, 8*n); + + // Step 2. Compute intermediate values. + // For j = 5 to 0 + // For i = n to 1 + // B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i + // A = MSB(64, B) + // R[i] = LSB(64, B) + AP4_AesBlockCipher block_cipher(kek, AP4_BlockCipher::DECRYPT); + for (int j=5; j>=0; j--) { + r = (AP4_UI08*)cleartext_key.UseData()+(n-1)*8; + for (int i=n; i>=1; i--) { + AP4_UI08 workspace[16]; + AP4_UI08 b[16]; + AP4_CopyMemory(workspace, a, 8); + workspace[7] ^= (n*j)+i; + AP4_CopyMemory(&workspace[8], r, 8); + block_cipher.ProcessBlock(workspace, b); + AP4_CopyMemory(a, b, 8); + AP4_CopyMemory(r, &b[8], 8); + r -= 8; + } + } + + // Step 3. Output results. + // If A is an appropriate initial value (see 2.2.3), + // Then + // For i = 1 to n + // P[i] = R[i] + // Else + // Return an error + for (unsigned int i=0; i<8; i++) { + if (a[i] != 0xA6) { + cleartext_key.SetDataSize(0); + return AP4_ERROR_INVALID_FORMAT; + } + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4KeyWrap.h b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4KeyWrap.h new file mode 100644 index 000000000..d0db038e9 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4KeyWrap.h @@ -0,0 +1,52 @@ +/***************************************************************** +| +| AP4 - Key Wrap Algorithms +| +| Copyright 2002-2009 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_KEY_WRAP_H_ +#define _AP4_KEY_WRAP_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Results.h" +#include "Ap4Types.h" +#include "Ap4DataBuffer.h" + +/*---------------------------------------------------------------------- +| functions ++---------------------------------------------------------------------*/ +AP4_Result AP4_AesKeyWrap(const AP4_UI08* kek, + const AP4_UI08* cleartext_key, + AP4_Size cleartext_key_size, + AP4_DataBuffer& wrapped_key); + +AP4_Result AP4_AesKeyUnwrap(const AP4_UI08* kek, + const AP4_UI08* wrapped_key, + AP4_Size wrapped_key_size, + AP4_DataBuffer& cleartext_key); + +#endif // _AP4_KEY_WRAP_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4StreamCipher.cpp b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4StreamCipher.cpp new file mode 100644 index 000000000..0b9320f5c --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4StreamCipher.cpp @@ -0,0 +1,410 @@ +/***************************************************************** +| +| AP4 - Stream Cipher +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4StreamCipher.h" +#include "Ap4Utils.h" + +/*---------------------------------------------------------------------- +| AP4_CtrStreamCipher::AP4_CtrStreamCipher ++---------------------------------------------------------------------*/ +AP4_CtrStreamCipher::AP4_CtrStreamCipher(AP4_BlockCipher* block_cipher, + const AP4_UI08* salt, + AP4_Size counter_size) : + m_StreamOffset(0), + m_CounterSize(counter_size), + m_BlockCipher(block_cipher) +{ + if (m_CounterSize > 16) m_CounterSize = 16; + + // use the salt to initialize the base counter + if (salt) { + // initialize the base counter with a salting key + AP4_CopyMemory(m_BaseCounter, salt, AP4_CIPHER_BLOCK_SIZE); + } else { + // initialize the base counter with zeros + AP4_SetMemory(m_BaseCounter, 0, AP4_CIPHER_BLOCK_SIZE); + } + + // reset the stream offset + SetStreamOffset(0); + SetIV(NULL); +} + +/*---------------------------------------------------------------------- +| AP4_CtrStreamCipher::~AP4_CtrStreamCipher ++---------------------------------------------------------------------*/ +AP4_CtrStreamCipher::~AP4_CtrStreamCipher() +{ + delete m_BlockCipher; +} + +/*---------------------------------------------------------------------- +| AP4_CtrStreamCipher::SetIV ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CtrStreamCipher::SetIV(const AP4_UI08* counter) +{ + if (counter) { + AP4_CopyMemory(&m_BaseCounter[AP4_CIPHER_BLOCK_SIZE-m_CounterSize], + counter, m_CounterSize); + } else { + AP4_SetMemory(&m_BaseCounter[AP4_CIPHER_BLOCK_SIZE-m_CounterSize], + 0, m_CounterSize); + } + + // for the stream offset back to 0 + return SetStreamOffset(0); +} + +/*---------------------------------------------------------------------- +| AP4_CtrStreamCipher::SetStreamOffset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CtrStreamCipher::SetStreamOffset(AP4_UI64 offset, + AP4_Cardinal* preroll) +{ + // do nothing if we're already at that offset + if (offset == m_StreamOffset) return AP4_SUCCESS; + + // update the offset + m_StreamOffset = offset; + + // update the key stream if necessary + if (m_StreamOffset & 0xF) { + UpdateKeyStream(); + } + + if (preroll != NULL) *preroll = 0; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_CtrStreamCipher::UpdateKeyStream ++---------------------------------------------------------------------*/ +void +AP4_CtrStreamCipher::UpdateKeyStream() +{ + // setup counter offset bytes + AP4_UI64 counter_offset = m_StreamOffset/AP4_CIPHER_BLOCK_SIZE; + AP4_UI08 counter_offset_bytes[8]; + AP4_BytesFromUInt64BE(counter_offset_bytes, counter_offset); + + // compute the new counter + AP4_UI08 counter_block[AP4_CIPHER_BLOCK_SIZE]; + unsigned int carry = 0; + for (unsigned int i=0; i<m_CounterSize; i++) { + unsigned int o = AP4_CIPHER_BLOCK_SIZE-1-i; + unsigned int x = m_BaseCounter[o]; + unsigned int y = (i<8)?counter_offset_bytes[7-i]:0; + unsigned int sum = x+y+carry; + counter_block[o] = (AP4_UI08)(sum&0xFF); + carry = ((sum >= 0x100)?1:0); + } + for (unsigned int i=m_CounterSize; i<AP4_CIPHER_BLOCK_SIZE; i++) { + unsigned int o = AP4_CIPHER_BLOCK_SIZE-1-i; + counter_block[o] = m_BaseCounter[o]; + } + + // compute the key block (x) from the counter block (c) + m_BlockCipher->ProcessBlock(counter_block, m_XBlock); +} + +/*---------------------------------------------------------------------- +| AP4_CtrStreamCipher::ProcessBuffer ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CtrStreamCipher::ProcessBuffer(const AP4_UI08* in, + AP4_Size in_size, + AP4_UI08* out, + AP4_Size* out_size /* = NULL */, + bool /* is_last_buffer */) +{ + if (m_BlockCipher == NULL) return AP4_ERROR_INVALID_STATE; + + if (out_size != NULL && *out_size < in_size) { + return AP4_ERROR_BUFFER_TOO_SMALL; + } + + // in CTR mode, the output is the same size as the input + if (out_size != NULL) *out_size = in_size; + + // process all the bytes in the buffer + while (in_size) { + // compute the number of bytes available in this chunk + AP4_UI32 index = (AP4_UI32)(m_StreamOffset & (AP4_CIPHER_BLOCK_SIZE-1)); + AP4_UI32 chunk; + + // update the key stream if we are on a boundary + if (index == 0) { + UpdateKeyStream(); + chunk = AP4_CIPHER_BLOCK_SIZE; + } + + // compute the number of bytes remaining in the chunk + chunk = AP4_CIPHER_BLOCK_SIZE - index; + if (chunk > in_size) chunk = in_size; + + // encrypt/decrypt the chunk + AP4_UI08* x = &m_XBlock[index]; + for (AP4_UI32 i = 0; i < chunk; i++) { + *out++ = *in++ ^ *x++; + } + + // update offset and size + m_StreamOffset += chunk; + in_size -= chunk; + } + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_CbcStreamCipher::AP4_CbcStreamCipher ++---------------------------------------------------------------------*/ +AP4_CbcStreamCipher::AP4_CbcStreamCipher(AP4_BlockCipher* block_cipher, + CipherDirection direction) : + m_Direction(direction), + m_StreamOffset(0), + m_OutputSkip(0), + m_BlockCipher(block_cipher), + m_Eos(false), + m_PrerollByteCount(0) +{ + AP4_SetMemory(m_Iv, 0, AP4_CIPHER_BLOCK_SIZE); + AP4_SetMemory(m_OutBlockCache, 0, AP4_CIPHER_BLOCK_SIZE); +} + +/*---------------------------------------------------------------------- +| AP4_CbcStreamCipher::~AP4_CbcStreamCipher ++---------------------------------------------------------------------*/ +AP4_CbcStreamCipher::~AP4_CbcStreamCipher() +{ + delete m_BlockCipher; +} + +/*---------------------------------------------------------------------- +| AP4_CbcStreamCipher::SetIV ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CbcStreamCipher::SetIV(const AP4_UI08* iv) +{ + AP4_CopyMemory(m_Iv, iv, AP4_CIPHER_BLOCK_SIZE); + m_StreamOffset = 0; + m_OutputSkip = 0; + m_Eos = false; + AP4_CopyMemory(m_OutBlockCache, m_Iv, AP4_CIPHER_BLOCK_SIZE); + m_PrerollByteCount = 0; + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_CbcStreamCipher::SetStreamOffset ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CbcStreamCipher::SetStreamOffset(AP4_UI64 offset, + AP4_Cardinal* preroll) +{ + // does not make sense for encryption + if (m_Direction == AP4_StreamCipher::ENCRYPT) return AP4_ERROR_NOT_SUPPORTED; + + // check params + if (preroll == NULL) return AP4_ERROR_INVALID_PARAMETERS; + + // reset the end of stream flag + m_Eos = false; + + // special cases + if (offset == 0) { + *preroll = 0; + return SetIV(m_Iv); + } + if (offset == m_StreamOffset) { + *preroll = m_PrerollByteCount; + m_OutputSkip = (AP4_Size)(offset%AP4_CIPHER_BLOCK_SIZE); + return AP4_SUCCESS; + } + + // other cases + if (offset < AP4_CIPHER_BLOCK_SIZE) { + // reset the IV to the output block cache + AP4_CopyMemory(m_OutBlockCache, m_Iv, AP4_CIPHER_BLOCK_SIZE); + m_PrerollByteCount = (AP4_Cardinal) offset; + } else { + m_PrerollByteCount = (AP4_Cardinal) ((offset%AP4_CIPHER_BLOCK_SIZE) + + AP4_CIPHER_BLOCK_SIZE); + } + + *preroll = m_PrerollByteCount; + m_StreamOffset = offset; + m_OutputSkip = (AP4_Size)(offset%AP4_CIPHER_BLOCK_SIZE); + return AP4_SUCCESS; +} + + +/*---------------------------------------------------------------------- +| AP4_CbcStreamCipher::ProcessBuffer ++---------------------------------------------------------------------*/ +AP4_Result +AP4_CbcStreamCipher::ProcessBuffer(const AP4_UI08* in, + AP4_Size in_size, + AP4_UI08* out, + AP4_Size* out_size, + bool is_last_buffer /* = false */) +{ + // check the parameters + if (out_size == NULL) return AP4_ERROR_INVALID_PARAMETERS; + + // check the state + if (m_BlockCipher == NULL || m_Eos) { + *out_size = 0; + return AP4_ERROR_INVALID_STATE; + } + if (is_last_buffer) m_Eos = true; + + // if there was a previous call to SetStreamOffset that set m_PrerollByteCount, + // we require that this call provides the at least entire preroll data + if (m_PrerollByteCount) { + if (in_size < m_PrerollByteCount) { + *out_size = 0; + return AP4_ERROR_NOT_ENOUGH_DATA; + } + } + + // compute how many blocks we span + AP4_UI64 start_block = m_StreamOffset/AP4_CIPHER_BLOCK_SIZE; + AP4_UI64 end_block = (m_StreamOffset+in_size-m_PrerollByteCount)/AP4_CIPHER_BLOCK_SIZE; + AP4_UI32 blocks_needed = (AP4_UI32)(end_block-start_block); + + if (m_Direction == ENCRYPT) { + // compute how many blocks we will need to produce + unsigned int padded_in_size = in_size; + AP4_UI08 pad_byte = 0; + if (is_last_buffer) { + ++blocks_needed; + pad_byte = AP4_CIPHER_BLOCK_SIZE-(AP4_UI08)((m_StreamOffset+in_size)%AP4_CIPHER_BLOCK_SIZE); + padded_in_size += pad_byte; + } + if (*out_size < blocks_needed*AP4_CIPHER_BLOCK_SIZE) { + *out_size = blocks_needed*AP4_CIPHER_BLOCK_SIZE; + return AP4_ERROR_BUFFER_TOO_SMALL; + } + *out_size = blocks_needed*AP4_CIPHER_BLOCK_SIZE; + + unsigned int position = (unsigned int)(m_StreamOffset%AP4_CIPHER_BLOCK_SIZE); + m_StreamOffset += in_size; + for (unsigned int x=0; x<padded_in_size; x++) { + if (x < in_size) { + m_InBlockCache[position] = in[x] ^ m_OutBlockCache[position]; + } else { + m_InBlockCache[position] = pad_byte ^ m_OutBlockCache[position]; + } + if (++position == AP4_CIPHER_BLOCK_SIZE) { + // encrypt and emit a block + m_BlockCipher->ProcessBlock(m_InBlockCache, m_OutBlockCache); + AP4_CopyMemory(out, m_OutBlockCache, AP4_CIPHER_BLOCK_SIZE); + out += AP4_CIPHER_BLOCK_SIZE; + position = 0; + } + } + } else { + // compute how many blocks we may produce + AP4_Size bytes_produced = blocks_needed*AP4_CIPHER_BLOCK_SIZE; + if (bytes_produced > m_OutputSkip) { + bytes_produced -= m_OutputSkip; + } + if (*out_size < bytes_produced) { + *out_size = bytes_produced; + return AP4_ERROR_BUFFER_TOO_SMALL; + } + *out_size = bytes_produced; + + // if we've just been seeked (SetStreamOffset), + if (m_PrerollByteCount > 0) { + if (m_PrerollByteCount >= AP4_CIPHER_BLOCK_SIZE) { + // fill the outblock cache with the first 16 bytes + AP4_CopyMemory(m_OutBlockCache, in, AP4_CIPHER_BLOCK_SIZE); + in += AP4_CIPHER_BLOCK_SIZE; + m_PrerollByteCount -= AP4_CIPHER_BLOCK_SIZE; + in_size -= AP4_CIPHER_BLOCK_SIZE; + } + + AP4_ASSERT(m_PrerollByteCount < 16); + + // fill m_InBlockCache with the input for the remaining m_PrerollByteCount + if (m_PrerollByteCount) { + AP4_CopyMemory(m_InBlockCache, in, m_PrerollByteCount); + in += m_PrerollByteCount; + in_size -= m_PrerollByteCount; + m_PrerollByteCount = 0; + } + } + + unsigned int position = (unsigned int)(m_StreamOffset%AP4_CIPHER_BLOCK_SIZE); + m_StreamOffset += in_size; + for (unsigned int x=0; x<in_size; x++) { + m_InBlockCache[position] = in[x]; + if (++position == AP4_CIPHER_BLOCK_SIZE) { + // decrypt a block + AP4_UI08 out_block[AP4_CIPHER_BLOCK_SIZE]; + m_BlockCipher->ProcessBlock(m_InBlockCache, out_block); + for (unsigned int y=0; y<AP4_CIPHER_BLOCK_SIZE; y++) { + out_block[y] ^= m_OutBlockCache[y]; + } + AP4_CopyMemory(m_OutBlockCache, m_InBlockCache, AP4_CIPHER_BLOCK_SIZE); + + // emit the block (or partial block) to the out buffer + unsigned int out_chunk = AP4_CIPHER_BLOCK_SIZE-m_OutputSkip; + AP4_CopyMemory(out, out_block+m_OutputSkip, out_chunk); + out += out_chunk; + position = 0; + m_OutputSkip = 0; + } + } + if (is_last_buffer && m_Direction == DECRYPT) { + // check that we have fed an integral number of blocks + if (m_StreamOffset%AP4_CIPHER_BLOCK_SIZE != 0) { + *out_size = 0; + return AP4_ERROR_INVALID_PARAMETERS; + } + + // remove the padding + AP4_UI08 pad_byte = out[-1]; + if (pad_byte == 0 || pad_byte > AP4_CIPHER_BLOCK_SIZE) { + *out_size = 0; + return AP4_ERROR_INVALID_FORMAT; + } + *out_size -= pad_byte; + } + } + + return AP4_SUCCESS; +} diff --git a/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4StreamCipher.h b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4StreamCipher.h new file mode 100644 index 000000000..9fcec8136 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/Crypto/Ap4StreamCipher.h @@ -0,0 +1,162 @@ +/***************************************************************** +| +| AP4 - Stream Cipher +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_STREAM_CIPHER_H_ +#define _AP4_STREAM_CIPHER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Protection.h" +#include "Ap4Results.h" +#include "Ap4Types.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +// we only support this for now +const unsigned int AP4_CIPHER_BLOCK_SIZE = 16; + +/*---------------------------------------------------------------------- +| AP4_StreamCipher interface ++---------------------------------------------------------------------*/ +class AP4_StreamCipher +{ +public: + // types + typedef enum { + ENCRYPT, + DECRYPT + } CipherDirection; + + // methods + virtual ~AP4_StreamCipher() {} + + virtual AP4_UI64 GetStreamOffset() = 0; + + virtual AP4_Result ProcessBuffer(const AP4_UI08* in, + AP4_Size in_size, + AP4_UI08* out, + AP4_Size* out_size, + bool is_last_buffer = false) = 0; + + // preroll gives the number of bytes you have to preroll your input and feed + // it through ProcessBuffer (in one shot) in order to be able to spit out + // the output at the given offset + virtual AP4_Result SetStreamOffset(AP4_UI64 offset, + AP4_Cardinal* preroll) = 0; + + virtual AP4_Result SetIV(const AP4_UI08* iv) = 0; + virtual const AP4_UI08* GetIV() = 0; +}; + + +/*---------------------------------------------------------------------- +| AP4_CtrStreamCipher ++---------------------------------------------------------------------*/ +class AP4_CtrStreamCipher : public AP4_StreamCipher +{ +public: + // methods + + /** + * The block cipher is passed with transfer of ownership (it will + * be destroyed when this object is destroyed). + */ + AP4_CtrStreamCipher(AP4_BlockCipher* block_cipher, + const AP4_UI08* salt, + AP4_Size counter_size); + ~AP4_CtrStreamCipher(); + + // AP4_StreamCipher implementation + virtual AP4_Result SetStreamOffset(AP4_UI64 offset, + AP4_Cardinal* preroll = NULL); + virtual AP4_UI64 GetStreamOffset() { return m_StreamOffset; } + virtual AP4_Result ProcessBuffer(const AP4_UI08* in, + AP4_Size in_size, + AP4_UI08* out, + AP4_Size* out_size = NULL, + bool is_last_buffer = false); + + virtual AP4_Result SetIV(const AP4_UI08* iv); + virtual const AP4_UI08* GetIV() { return m_BaseCounter; } + +private: + // methods + void SetCounterOffset(AP4_UI32 offset); + void UpdateKeyStream(); + + // members + AP4_UI64 m_StreamOffset; + AP4_Size m_CounterSize; + AP4_UI08 m_BaseCounter[AP4_CIPHER_BLOCK_SIZE]; + AP4_UI08 m_XBlock[AP4_CIPHER_BLOCK_SIZE]; + AP4_BlockCipher* m_BlockCipher; +}; + +/*---------------------------------------------------------------------- +| AP4_CbcStreamCipher ++---------------------------------------------------------------------*/ +class AP4_CbcStreamCipher : public AP4_StreamCipher +{ +public: + // methods + + /** + * The block cipher is passed with transfer of ownership (it will + * be destroyed when this object is destroyed). + */ + AP4_CbcStreamCipher(AP4_BlockCipher* block_cipher, CipherDirection direction); + ~AP4_CbcStreamCipher(); + + // AP4_StreamCipher implementation + virtual AP4_Result SetStreamOffset(AP4_UI64 offset, + AP4_Cardinal* preroll); + virtual AP4_UI64 GetStreamOffset() { return m_StreamOffset; } + virtual AP4_Result ProcessBuffer(const AP4_UI08* in, + AP4_Size in_size, + AP4_UI08* out, + AP4_Size* out_size, + bool is_last_buffer = false); + virtual AP4_Result SetIV(const AP4_UI08* iv); + virtual const AP4_UI08* GetIV() { return m_Iv; }; + +private: + // members + CipherDirection m_Direction; + AP4_UI64 m_StreamOffset; + AP4_Size m_OutputSkip; + AP4_UI08 m_InBlockCache[AP4_CIPHER_BLOCK_SIZE]; + AP4_UI08 m_OutBlockCache[AP4_CIPHER_BLOCK_SIZE]; + AP4_UI08 m_Iv[AP4_CIPHER_BLOCK_SIZE]; + AP4_BlockCipher* m_BlockCipher; + bool m_Eos; + AP4_Cardinal m_PrerollByteCount; +}; + +#endif // _AP4_STREAM_CIPHER_H_ diff --git a/src/filters/parser/MP4Splitter/AP4/Source/MetaData/Ap4MetaData.cpp b/src/filters/parser/MP4Splitter/AP4/Source/MetaData/Ap4MetaData.cpp new file mode 100644 index 000000000..5f97839d9 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/MetaData/Ap4MetaData.cpp @@ -0,0 +1,1736 @@ +/*****************************************************************
+|
+| AP4 - MetaData
+|
+| Copyright 2002-2008 Axiomatic Systems, LLC
+|
+|
+| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
+|
+| Unless you have obtained Bento4 under a difference license,
+| this version of Bento4 is Bento4|GPL.
+| Bento4|GPL is free software; you can redistribute it and/or modify
+| it under the terms of the GNU General Public License as published by
+| the Free Software Foundation; either version 2, or (at your option)
+| any later version.
+|
+| Bento4|GPL is distributed in the hope that it will be useful,
+| but WITHOUT ANY WARRANTY; without even the implied warranty of
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+| GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License
+| along with Bento4|GPL; see the file COPYING. If not, write to the
+| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+| 02111-1307, USA.
+|
+****************************************************************/
+
+/*----------------------------------------------------------------------
+| includes
++---------------------------------------------------------------------*/
+#include "Ap4File.h"
+#include "Ap4Movie.h"
+#include "Ap4MetaData.h"
+#include "Ap4ContainerAtom.h"
+#include "Ap4MoovAtom.h"
+#include "Ap4HdlrAtom.h"
+#include "Ap4DataBuffer.h"
+#include "Ap4Utils.h"
+#include "Ap4String.h"
+
+/*----------------------------------------------------------------------
+| dynamic cast support
++---------------------------------------------------------------------*/
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_3GppLocalizedStringAtom)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DcfdAtom)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DcfStringAtom)
+AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_DataAtom)
+
+/*----------------------------------------------------------------------
+| metadata keys
++---------------------------------------------------------------------*/
+static const AP4_MetaData::KeyInfo AP4_MetaData_KeyInfos [] = {
+ {"Name", "Name", AP4_ATOM_TYPE_cNAM, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Artist", "Artist", AP4_ATOM_TYPE_cART, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"AlbumArtist", "Album Artist", AP4_ATOM_TYPE_aART, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Composer", "Composer", AP4_ATOM_TYPE_cCOM, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Writer", "Writer", AP4_ATOM_TYPE_cWRT, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Album", "Album", AP4_ATOM_TYPE_cALB, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"GenreCode", "Genre", AP4_ATOM_TYPE_GNRE, AP4_MetaData::Value::TYPE_BINARY},
+ {"GenreName", "Genre", AP4_ATOM_TYPE_cGEN, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Grouping", "Grouping", AP4_ATOM_TYPE_cGRP, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Date", "Date", AP4_ATOM_TYPE_cDAY, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Tool", "Encoding Tool", AP4_ATOM_TYPE_cTOO, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Comment", "Comment", AP4_ATOM_TYPE_cCMT, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Lyrics", "Lyrics", AP4_ATOM_TYPE_cLYR, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Copyright", "Copyright", AP4_ATOM_TYPE_CPRT, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Track", "Track Number", AP4_ATOM_TYPE_TRKN, AP4_MetaData::Value::TYPE_BINARY},
+ {"Disc", "Disc Number", AP4_ATOM_TYPE_DISK, AP4_MetaData::Value::TYPE_BINARY},
+ {"Cover", "Cover Art", AP4_ATOM_TYPE_COVR, AP4_MetaData::Value::TYPE_BINARY},
+ {"Description", "Description", AP4_ATOM_TYPE_DESC, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Rating", "Rating", AP4_ATOM_TYPE_RTNG, AP4_MetaData::Value::TYPE_INT_08_BE},
+ {"Tempo", "Tempo", AP4_ATOM_TYPE_TMPO, AP4_MetaData::Value::TYPE_INT_16_BE},
+ {"Compilation", "Compilation", AP4_ATOM_TYPE_CPIL, AP4_MetaData::Value::TYPE_INT_08_BE},
+ {"IsGapless", "Is Gapless", AP4_ATOM_TYPE_PGAP, AP4_MetaData::Value::TYPE_INT_08_BE},
+ {"Title", "Title", AP4_ATOM_TYPE_TITL, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Description", "Description", AP4_ATOM_TYPE_DSCP, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"StoreFrontID", "Store Front ID", AP4_ATOM_TYPE_sfID, AP4_MetaData::Value::TYPE_INT_32_BE},
+ {"FileKind", "File Kind", AP4_ATOM_TYPE_STIK, AP4_MetaData::Value::TYPE_INT_08_BE},
+ {"ShowName", "Show Name", AP4_ATOM_TYPE_TVSH, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"ShowSeason", "Show Season Number", AP4_ATOM_TYPE_TVSN, AP4_MetaData::Value::TYPE_INT_32_BE},
+ {"ShowEpisodeNumber", "Show Episode Number", AP4_ATOM_TYPE_TVES, AP4_MetaData::Value::TYPE_INT_32_BE},
+ {"ShowEpisodeName", "Show Episode Name", AP4_ATOM_TYPE_TVEN, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"TVNetworkName", "TV Network Name", AP4_ATOM_TYPE_TVNN, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"IsPodcast", "Is a Podcast", AP4_ATOM_TYPE_PCST, AP4_MetaData::Value::TYPE_INT_08_BE},
+ {"PodcastUrl", "Podcast URL", AP4_ATOM_TYPE_PURL, AP4_MetaData::Value::TYPE_BINARY},
+ {"PodcastGuid", "Podcast GUID", AP4_ATOM_TYPE_EGID, AP4_MetaData::Value::TYPE_BINARY},
+ {"PodcastCategory", "Podcast Category", AP4_ATOM_TYPE_CATG, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Keywords", "Keywords", AP4_ATOM_TYPE_KEYW, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"PurchaseDate", "Purchase Date", AP4_ATOM_TYPE_PURD, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"IconUri", "Icon URI", AP4_ATOM_TYPE_ICNU, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"InfoUrl", "Info URL", AP4_ATOM_TYPE_INFU, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"CoverUri", "Cover Art URI", AP4_ATOM_TYPE_CVRU, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"LyricsUri", "Lyrics URI", AP4_ATOM_TYPE_LRCU, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Duration", "Duration", AP4_ATOM_TYPE_DCFD, AP4_MetaData::Value::TYPE_INT_32_BE},
+ {"Performer", "Performer", AP4_ATOM_TYPE_PERF, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+ {"Author", "Author", AP4_ATOM_TYPE_AUTH, AP4_MetaData::Value::TYPE_STRING_UTF_8},
+};
+AP4_Array<AP4_MetaData::KeyInfo> AP4_MetaData::KeyInfos(
+ AP4_MetaData_KeyInfos,
+ sizeof(AP4_MetaData_KeyInfos)/sizeof(KeyInfo));
+
+/*----------------------------------------------------------------------
+| genre IDs
++---------------------------------------------------------------------*/
+static const char* const Ap4Id3Genres[] =
+{
+ "Blues",
+ "Classic Rock",
+ "Country",
+ "Dance",
+ "Disco",
+ "Funk",
+ "Grunge",
+ "Hip-Hop",
+ "Jazz",
+ "Metal",
+ "New Age",
+ "Oldies",
+ "Other",
+ "Pop",
+ "R&B",
+ "Rap",
+ "Reggae",
+ "Rock",
+ "Techno",
+ "Industrial",
+ "Alternative",
+ "Ska",
+ "Death Metal",
+ "Pranks",
+ "Soundtrack",
+ "Euro-Techno",
+ "Ambient",
+ "Trip-Hop",
+ "Vocal",
+ "Jazz+Funk",
+ "Fusion",
+ "Trance",
+ "Classical",
+ "Instrumental",
+ "Acid",
+ "House",
+ "Game",
+ "Sound Clip",
+ "Gospel",
+ "Noise",
+ "AlternRock",
+ "Bass",
+ "Soul",
+ "Punk",
+ "Space",
+ "Meditative",
+ "Instrumental Pop",
+ "Instrumental Rock",
+ "Ethnic",
+ "Gothic",
+ "Darkwave",
+ "Techno-Industrial",
+ "Electronic",
+ "Pop-Folk",
+ "Eurodance",
+ "Dream",
+ "Southern Rock",
+ "Comedy",
+ "Cult",
+ "Gangsta",
+ "Top 40",
+ "Christian Rap",
+ "Pop/Funk",
+ "Jungle",
+ "Native American",
+ "Cabaret",
+ "New Wave",
+ "Psychadelic",
+ "Rave",
+ "Showtunes",
+ "Trailer",
+ "Lo-Fi",
+ "Tribal",
+ "Acid Punk",
+ "Acid Jazz",
+ "Polka",
+ "Retro",
+ "Musical",
+ "Rock & Roll",
+ "Hard Rock",
+ "Folk",
+ "Folk-Rock",
+ "National Folk",
+ "Swing",
+ "Fast Fusion",
+ "Bebob",
+ "Latin",
+ "Revival",
+ "Celtic",
+ "Bluegrass",
+ "Avantgarde",
+ "Gothic Rock",
+ "Progressive Rock",
+ "Psychedelic Rock",
+ "Symphonic Rock",
+ "Slow Rock",
+ "Big Band",
+ "Chorus",
+ "Easy Listening",
+ "Acoustic",
+ "Humour",
+ "Speech",
+ "Chanson",
+ "Opera",
+ "Chamber Music",
+ "Sonata",
+ "Symphony",
+ "Booty Bass",
+ "Primus",
+ "Porn Groove",
+ "Satire",
+ "Slow Jam",
+ "Club",
+ "Tango",
+ "Samba",
+ "Folklore",
+ "Ballad",
+ "Power Ballad",
+ "Rhythmic Soul",
+ "Freestyle",
+ "Duet",
+ "Punk Rock",
+ "Drum Solo",
+ "Acapella",
+ "Euro-House",
+ "Dance Hall"
+};
+
+static const char*
+Ap4StikNames[] = {
+ "Movie", // 0
+ "Normal", // 1
+ "Audiobook", // 2
+ "?", // 3
+ "?", // 4
+ "Whacked Bookmark", // 5
+ "Music Video", // 6
+ "?", // 7
+ "?", // 8
+ "Short Film", // 9
+ "TV Show", // 10
+ "Booklet", // 11
+ "?", // 12
+ "?", // 13
+ "Ring Tone" // 14
+};
+
+
+/* sfID Store Front country
+ Australia => 143460,
+ Austria => 143445,
+ Belgium => 143446,
+ Canada => 143455,
+ Denmark => 143458,
+ Finland => 143447,
+ France => 143442,
+ Germany => 143443,
+ Greece => 143448,
+ Ireland => 143449,
+ Italy => 143450,
+ Japan => 143462,
+ Luxembourg => 143451,
+ Netherlands => 143452,
+ Norway => 143457,
+ Portugal => 143453,
+ Spain => 143454,
+ Sweden => 143456,
+ Switzerland => 143459,
+ UK => 143444,
+ USA => 143441,
+*/
+
+/*----------------------------------------------------------------------
+| constants
++---------------------------------------------------------------------*/
+const AP4_Size AP4_DATA_ATOM_MAX_SIZE = 0x40000000;
+
+/*----------------------------------------------------------------------
+| 3GPP localized string atoms
++---------------------------------------------------------------------*/
+const AP4_Atom::Type AP4_MetaDataAtomTypeHandler::_3gppLocalizedStringTypes[] = {
+ AP4_ATOM_TYPE_TITL,
+ AP4_ATOM_TYPE_DSCP,
+ AP4_ATOM_TYPE_CPRT,
+ AP4_ATOM_TYPE_PERF,
+ AP4_ATOM_TYPE_AUTH,
+ AP4_ATOM_TYPE_GNRE
+};
+const AP4_MetaDataAtomTypeHandler::TypeList AP4_MetaDataAtomTypeHandler::_3gppLocalizedStringTypeList = {
+ _3gppLocalizedStringTypes,
+ sizeof(_3gppLocalizedStringTypes)/sizeof(_3gppLocalizedStringTypes[0])
+};
+
+/*----------------------------------------------------------------------
+| other 3GPP atoms
++---------------------------------------------------------------------*/
+const AP4_Atom::Type AP4_MetaDataAtomTypeHandler::_3gppOtherTypes[] = {
+ AP4_ATOM_TYPE_RTNG,
+ AP4_ATOM_TYPE_CLSF,
+ AP4_ATOM_TYPE_KYWD,
+ AP4_ATOM_TYPE_LOCI,
+ AP4_ATOM_TYPE_ALBM,
+ AP4_ATOM_TYPE_YRRC,
+};
+const AP4_MetaDataAtomTypeHandler::TypeList AP4_MetaDataAtomTypeHandler::_3gppOtherTypeList = {
+ _3gppOtherTypes,
+ sizeof(_3gppOtherTypes)/sizeof(_3gppOtherTypes[0])
+};
+
+/*----------------------------------------------------------------------
+| DCF string atoms
++---------------------------------------------------------------------*/
+const AP4_Atom::Type AP4_MetaDataAtomTypeHandler::DcfStringTypes[] = {
+ AP4_ATOM_TYPE_ICNU,
+ AP4_ATOM_TYPE_INFU,
+ AP4_ATOM_TYPE_CVRU,
+ AP4_ATOM_TYPE_LRCU
+};
+const AP4_MetaDataAtomTypeHandler::TypeList AP4_MetaDataAtomTypeHandler::DcfStringTypeList = {
+ DcfStringTypes,
+ sizeof(DcfStringTypes)/sizeof(DcfStringTypes[0])
+};
+
+/*----------------------------------------------------------------------
+| atom type lists
++---------------------------------------------------------------------*/
+const AP4_Atom::Type AP4_MetaDataAtomTypeHandler::IlstTypes[] =
+{
+ AP4_ATOM_TYPE_dddd,
+ AP4_ATOM_TYPE_cNAM,
+ AP4_ATOM_TYPE_cART,
+ AP4_ATOM_TYPE_cCOM,
+ AP4_ATOM_TYPE_cWRT,
+ AP4_ATOM_TYPE_cALB,
+ AP4_ATOM_TYPE_cGEN,
+ AP4_ATOM_TYPE_cGRP,
+ AP4_ATOM_TYPE_cDAY,
+ AP4_ATOM_TYPE_cTOO,
+ AP4_ATOM_TYPE_cCMT,
+ AP4_ATOM_TYPE_CPRT,
+ AP4_ATOM_TYPE_TRKN,
+ AP4_ATOM_TYPE_DISK,
+ AP4_ATOM_TYPE_COVR,
+ AP4_ATOM_TYPE_DESC,
+ AP4_ATOM_TYPE_GNRE,
+ AP4_ATOM_TYPE_CPIL,
+ AP4_ATOM_TYPE_TMPO,
+ AP4_ATOM_TYPE_RTNG,
+ AP4_ATOM_TYPE_apID,
+ AP4_ATOM_TYPE_cnID,
+ AP4_ATOM_TYPE_cmID,
+ AP4_ATOM_TYPE_atID,
+ AP4_ATOM_TYPE_plID,
+ AP4_ATOM_TYPE_geID,
+ AP4_ATOM_TYPE_sfID,
+ AP4_ATOM_TYPE_akID,
+ AP4_ATOM_TYPE_aART,
+ AP4_ATOM_TYPE_TVNN,
+ AP4_ATOM_TYPE_TVSH,
+ AP4_ATOM_TYPE_TVEN,
+ AP4_ATOM_TYPE_TVSN,
+ AP4_ATOM_TYPE_TVES,
+ AP4_ATOM_TYPE_STIK,
+ AP4_ATOM_TYPE_PGAP,
+ AP4_ATOM_TYPE_PCST,
+ AP4_ATOM_TYPE_PURD,
+ AP4_ATOM_TYPE_PURL,
+ AP4_ATOM_TYPE_EGID,
+ AP4_ATOM_TYPE_SONM,
+ AP4_ATOM_TYPE_SOAL,
+ AP4_ATOM_TYPE_SOAR,
+ AP4_ATOM_TYPE_SOAA,
+ AP4_ATOM_TYPE_SOCO,
+ AP4_ATOM_TYPE_SOSN
+};
+const AP4_MetaDataAtomTypeHandler::TypeList AP4_MetaDataAtomTypeHandler::IlstTypeList = {
+ IlstTypes,
+ sizeof(IlstTypes)/sizeof(IlstTypes[0])
+};
+
+/*----------------------------------------------------------------------
+| AP4_MetaDataAtomTypeHandler::CreateAtom
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaDataAtomTypeHandler::CreateAtom(AP4_Atom::Type type,
+ AP4_UI32 size,
+ AP4_ByteStream& stream,
+ AP4_Atom::Type context,
+ AP4_Atom*& atom)
+{
+ atom = NULL;
+
+ if (context == AP4_ATOM_TYPE_ILST) {
+ if (IsTypeInList(type, IlstTypeList)) {
+ m_AtomFactory->PushContext(type);
+ atom = AP4_ContainerAtom::Create(type, size, false, false, stream, *m_AtomFactory);
+ m_AtomFactory->PopContext();
+ }
+ } else if (type == AP4_ATOM_TYPE_DATA) {
+ if (IsTypeInList(context, IlstTypeList)) {
+ atom = new AP4_DataAtom(size, stream);
+ }
+ } else if (context == AP4_ATOM_TYPE_dddd) {
+ if (type == AP4_ATOM_TYPE_MEAN || type == AP4_ATOM_TYPE_NAME) {
+ atom = new AP4_MetaDataStringAtom(type, size, stream);
+ }
+ } else if (context == AP4_ATOM_TYPE_UDTA) {
+ if (IsTypeInList(type, _3gppLocalizedStringTypeList)) {
+ atom = AP4_3GppLocalizedStringAtom::Create(type, size, stream);
+ } else if (IsTypeInList(type, DcfStringTypeList)) {
+ atom = AP4_DcfStringAtom::Create(type, size, stream);
+ } else if (type == AP4_ATOM_TYPE_DCFD) {
+ atom = AP4_DcfdAtom::Create(size, stream);
+ }
+ }
+
+ return atom?AP4_SUCCESS:AP4_FAILURE;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaDataAtomTypeHandler::IsTypeInList
++---------------------------------------------------------------------*/
+bool
+AP4_MetaDataAtomTypeHandler::IsTypeInList(AP4_Atom::Type type, const AP4_MetaDataAtomTypeHandler::TypeList& list)
+{
+ for (unsigned int i=0; i<list.m_Size; i++) {
+ if (type == list.m_Types[i]) return true;
+ }
+ return false;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::AP4_MetaData
++---------------------------------------------------------------------*/
+AP4_MetaData::AP4_MetaData(AP4_File* file)
+{
+ // get the file's movie
+ AP4_Movie* movie = file->GetMovie();
+
+ // handle the movie's metadata if there is a movie in the file
+ if (movie) {
+ AP4_MoovAtom* moov = movie->GetMoovAtom();
+ if (moov == NULL) return;
+ ParseMoov(moov);
+ } else {
+ // if we don't have a movie, try to show metadata from a udta atom
+ AP4_List<AP4_Atom>& top_level_atoms = file->GetTopLevelAtoms();
+
+ AP4_List<AP4_Atom>::Item* atom_item = top_level_atoms.FirstItem();
+ while (atom_item) {
+ AP4_ContainerAtom* container = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom_item->GetData());
+ if (container) {
+ // look for a udta in a DCF layout
+ AP4_Atom* udta = container->FindChild("odhe/udta");
+ if (udta) {
+ AP4_ContainerAtom* udta_container = AP4_DYNAMIC_CAST(AP4_ContainerAtom, udta);
+ if (udta_container) {
+ ParseUdta(udta_container, "dcf");
+ }
+ }
+ }
+ atom_item = atom_item->GetNext();
+ }
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::ParseMoov
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::ParseMoov(AP4_MoovAtom* moov)
+{
+ // look for a 'meta' atom with 'hdlr' type 'mdir'
+ AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, moov->FindChild("udta/meta/hdlr"));
+ if (hdlr == NULL || hdlr->GetHandlerType() != AP4_HANDLER_TYPE_MDIR) return AP4_ERROR_NO_SUCH_ITEM;
+
+ // get the list of entries
+ AP4_ContainerAtom* ilst = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->FindChild("udta/meta/ilst"));
+ if (ilst == NULL) return AP4_ERROR_NO_SUCH_ITEM;
+
+ AP4_List<AP4_Atom>::Item* ilst_item = ilst->GetChildren().FirstItem();
+ while (ilst_item) {
+ AP4_ContainerAtom* entry_atom = AP4_DYNAMIC_CAST(AP4_ContainerAtom, ilst_item->GetData());
+ if (entry_atom) {
+ AddIlstEntries(entry_atom, "meta");
+ }
+ ilst_item = ilst_item->GetNext();
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::ParseUdta
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::ParseUdta(AP4_ContainerAtom* udta, const char* namespc)
+{
+ // check that the atom is indeed a 'udta' atom
+ if (udta->GetType() != AP4_ATOM_TYPE_UDTA) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+
+ AP4_List<AP4_Atom>::Item* udta_item = udta->GetChildren().FirstItem();
+ for (; udta_item; udta_item = udta_item->GetNext()) {
+ AP4_3GppLocalizedStringAtom* _3gpp_atom = AP4_DYNAMIC_CAST(AP4_3GppLocalizedStringAtom, udta_item->GetData());
+ if (_3gpp_atom) {
+ Add3GppEntry(_3gpp_atom, namespc);
+ continue;
+ }
+
+ AP4_DcfStringAtom* dcfs_atom = AP4_DYNAMIC_CAST(AP4_DcfStringAtom, udta_item->GetData());
+ if (dcfs_atom) {
+ AddDcfStringEntry(dcfs_atom, namespc);
+ continue;
+ }
+
+ AP4_DcfdAtom* dcfd_atom = AP4_DYNAMIC_CAST(AP4_DcfdAtom, udta_item->GetData());
+ if (dcfd_atom) {
+ AddDcfdEntry(dcfd_atom, namespc);
+ }
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::~AP4_MetaData
++---------------------------------------------------------------------*/
+AP4_MetaData::~AP4_MetaData()
+{
+ m_Entries.DeleteReferences();
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::ResolveKeyName
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::ResolveKeyName(AP4_Atom::Type atom_type, AP4_String& value)
+{
+ const char* key_name = NULL;
+ char four_cc[5];
+
+ // look for a match in the key infos
+ for (unsigned int i=0;
+ i<sizeof(AP4_MetaData_KeyInfos)/sizeof(AP4_MetaData_KeyInfos[0]);
+ i++) {
+ if (AP4_MetaData_KeyInfos[i].four_cc == atom_type) {
+ key_name = AP4_MetaData_KeyInfos[i].name;
+ break;
+ }
+ }
+ if (key_name == NULL) {
+ // this key was not found in the key infos, create a name for it
+ AP4_FormatFourChars(four_cc, (AP4_UI32)atom_type);
+ key_name = four_cc;
+ }
+ value = key_name;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::AddIlstEntries
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::AddIlstEntries(AP4_ContainerAtom* atom, const char* namespc)
+{
+ AP4_MetaData::Value* value = NULL;
+
+ if (atom->GetType() == AP4_ATOM_TYPE_dddd) {
+ // look for the namespace
+ AP4_MetaDataStringAtom* mean = static_cast<AP4_MetaDataStringAtom*>(atom->GetChild(AP4_ATOM_TYPE_MEAN));
+ if (mean == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // look for the name
+ AP4_MetaDataStringAtom* name = static_cast<AP4_MetaDataStringAtom*>(atom->GetChild(AP4_ATOM_TYPE_NAME));
+ if (name == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // get the value
+ AP4_DataAtom* data_atom = static_cast<AP4_DataAtom*>(atom->GetChild(AP4_ATOM_TYPE_DATA));
+ value = new AP4_AtomMetaDataValue(data_atom, atom->GetType());
+ if (value == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ return m_Entries.Add(new Entry(name->GetValue().GetChars(),
+ mean->GetValue().GetChars(),
+ value));
+ } else {
+ const char* key_name = NULL;
+ char four_cc[5];
+
+ // convert the atom type to a name
+ AP4_FormatFourChars(four_cc, (AP4_UI32)atom->GetType());
+ key_name = four_cc;
+
+ // add one entry for each data atom
+ AP4_List<AP4_Atom>::Item* data_item = atom->GetChildren().FirstItem();
+ while (data_item) {
+ AP4_Atom* item_atom = data_item->GetData();
+ if (item_atom->GetType() == AP4_ATOM_TYPE_DATA) {
+ AP4_DataAtom* data_atom = static_cast<AP4_DataAtom*>(item_atom);
+ value = new AP4_AtomMetaDataValue(data_atom, atom->GetType());
+ m_Entries.Add(new Entry(key_name, namespc, value));
+ }
+ data_item = data_item->GetNext();
+ }
+
+ return AP4_SUCCESS;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Add3GppEntry
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Add3GppEntry(AP4_3GppLocalizedStringAtom* atom, const char* namespc)
+{
+ AP4_String key_name;
+ ResolveKeyName(atom->GetType(), key_name);
+
+ const char* language = NULL;
+ if (atom->GetLanguage()[0]) {
+ language = atom->GetLanguage();
+ }
+ AP4_MetaData::Value* value = new AP4_StringMetaDataValue(atom->GetValue().GetChars(),
+ language);
+ m_Entries.Add(new Entry(key_name.GetChars(), namespc, value));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::AddDcfStringEntry
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::AddDcfStringEntry(AP4_DcfStringAtom* atom, const char* namespc)
+{
+ AP4_String key_name;
+ ResolveKeyName(atom->GetType(), key_name);
+
+ AP4_MetaData::Value* value = new AP4_StringMetaDataValue(atom->GetValue().GetChars());
+ m_Entries.Add(new Entry(key_name.GetChars(), namespc, value));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::AddDcfdEntry
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::AddDcfdEntry(AP4_DcfdAtom* atom, const char* namespc)
+{
+ AP4_String key_name;
+ ResolveKeyName(atom->GetType(), key_name);
+
+ AP4_MetaData::Value* value = new AP4_IntegerMetaDataValue(AP4_MetaData::Value::TYPE_INT_32_BE,
+ atom->GetDuration());
+ m_Entries.Add(new Entry(key_name.GetChars(), namespc, value));
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Value::MapDataTypeToCategory
++---------------------------------------------------------------------*/
+AP4_MetaData::Value::TypeCategory
+AP4_MetaData::Value::MapTypeToCategory(Type type)
+{
+ switch (type) {
+ case AP4_MetaData::Value::TYPE_INT_08_BE:
+ case AP4_MetaData::Value::TYPE_INT_16_BE:
+ case AP4_MetaData::Value::TYPE_INT_32_BE:
+ return AP4_MetaData::Value::TYPE_CATEGORY_INTEGER;
+
+ case AP4_MetaData::Value::TYPE_STRING_UTF_8:
+ case AP4_MetaData::Value::TYPE_STRING_UTF_16:
+ case AP4_MetaData::Value::TYPE_STRING_PASCAL:
+ return AP4_MetaData::Value::TYPE_CATEGORY_STRING;
+
+ case AP4_MetaData::Value::TYPE_FLOAT_32_BE:
+ case AP4_MetaData::Value::TYPE_FLOAT_64_BE:
+ return AP4_MetaData::Value::TYPE_CATEGORY_FLOAT;
+
+ default:
+ return AP4_MetaData::Value::TYPE_CATEGORY_BINARY;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Value::GetTypeCategory
++---------------------------------------------------------------------*/
+AP4_MetaData::Value::TypeCategory
+AP4_MetaData::Value::GetTypeCategory() const
+{
+ return MapTypeToCategory(m_Type);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::ToAtom
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Entry::ToAtom(AP4_Atom*& atom) const
+{
+ atom = NULL;
+
+ if (m_Value == NULL) {
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+
+ if (m_Key.GetNamespace() == "meta") {
+ // convert the name into an atom type
+ if (m_Key.GetName().GetLength() != 4) {
+ // the name is not in the right format
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+ AP4_Atom::Type atom_type = AP4_Atom::TypeFromString(m_Key.GetName().GetChars());
+
+ // create a container atom for the data
+ AP4_ContainerAtom* container = new AP4_ContainerAtom(atom_type);
+
+ // add the data atom
+ AP4_DataAtom* data = new AP4_DataAtom(*m_Value);
+ container->AddChild(data);
+
+ atom = container;
+ return AP4_SUCCESS;
+ } else if (m_Key.GetNamespace() == "dcf") {
+ // convert the name into an atom type
+ if (m_Key.GetName().GetLength() != 4) {
+ // the name is not in the right format
+ return AP4_ERROR_INVALID_PARAMETERS;
+ }
+ AP4_Atom::Type atom_type = AP4_Atom::TypeFromString(m_Key.GetName().GetChars());
+
+ if (AP4_MetaDataAtomTypeHandler::IsTypeInList(atom_type,
+ AP4_MetaDataAtomTypeHandler::DcfStringTypeList)) {
+ AP4_String atom_value = m_Value->ToString();
+ atom = new AP4_DcfStringAtom(atom_type, atom_value.GetChars());
+ return AP4_SUCCESS;
+ } else if (AP4_MetaDataAtomTypeHandler::IsTypeInList(atom_type,
+ AP4_MetaDataAtomTypeHandler::_3gppLocalizedStringTypeList)) {
+ AP4_String atom_value = m_Value->ToString();
+ const char* language = "eng"; // default
+ if (m_Value->GetLanguage().GetLength() != 0) {
+ language = m_Value->GetLanguage().GetChars();
+ }
+ atom = new AP4_3GppLocalizedStringAtom(atom_type, language, atom_value.GetChars());
+ return AP4_SUCCESS;
+ } else if (atom_type == AP4_ATOM_TYPE_DCFD) {
+ atom = new AP4_DcfdAtom(m_Value->ToInteger());
+ return AP4_SUCCESS;
+ }
+
+ // not supported
+ return AP4_ERROR_NOT_SUPPORTED;
+ } else {
+ // create a '----' atom
+ AP4_ContainerAtom* container = new AP4_ContainerAtom(AP4_ATOM_TYPE_dddd);
+
+ // add a 'mean' string
+ container->AddChild(new AP4_MetaDataStringAtom(AP4_ATOM_TYPE_MEAN, m_Key.GetNamespace().GetChars()));
+
+ // add a 'name' string
+ container->AddChild(new AP4_MetaDataStringAtom(AP4_ATOM_TYPE_NAME, m_Key.GetName().GetChars()));
+
+ // add the data atom
+ AP4_DataAtom* data = new AP4_DataAtom(*m_Value);
+ container->AddChild(data);
+
+ atom = container;
+ return AP4_SUCCESS;
+ }
+
+ return AP4_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::FindInIlst
++---------------------------------------------------------------------*/
+AP4_ContainerAtom*
+AP4_MetaData::Entry::FindInIlst(AP4_ContainerAtom* ilst) const
+{
+ if (m_Key.GetNamespace() == "meta") {
+ AP4_Atom::Type atom_type = AP4_Atom::TypeFromString(m_Key.GetName().GetChars());
+ return AP4_DYNAMIC_CAST(AP4_ContainerAtom, ilst->GetChild(atom_type));
+ } else {
+ AP4_List<AP4_Atom>::Item* ilst_item = ilst->GetChildren().FirstItem();
+ while (ilst_item) {
+ AP4_ContainerAtom* entry_atom = AP4_DYNAMIC_CAST(AP4_ContainerAtom, ilst_item->GetData());
+ if (entry_atom) {
+ AP4_MetaDataStringAtom* mean = static_cast<AP4_MetaDataStringAtom*>(entry_atom->GetChild(AP4_ATOM_TYPE_MEAN));
+ AP4_MetaDataStringAtom* name = static_cast<AP4_MetaDataStringAtom*>(entry_atom->GetChild(AP4_ATOM_TYPE_NAME));
+ if (mean && name &&
+ mean->GetValue() == m_Key.GetNamespace() &&
+ name->GetValue() == m_Key.GetName()) {
+ return entry_atom;
+ }
+ }
+ ilst_item = ilst_item->GetNext();
+ }
+ }
+
+ // not found
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::AddToFileIlst
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Entry::AddToFileIlst(AP4_File& file, AP4_Ordinal index)
+{
+ // check that we have a correct entry
+ if (m_Value == NULL) return AP4_ERROR_INVALID_STATE;
+
+ // convert the entry into an atom
+ AP4_Atom* atom;
+ AP4_Result result = ToAtom(atom);
+ if (AP4_FAILED(result)) return result;
+ AP4_ContainerAtom* entry_atom = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
+ if (entry_atom == NULL) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+
+ // look for the 'moov'
+ AP4_Movie* movie = file.GetMovie();
+ if (movie == NULL) return AP4_ERROR_INVALID_FORMAT;
+ AP4_MoovAtom* moov = movie->GetMoovAtom();
+ if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // look for 'udta', and create if it does not exist
+ AP4_ContainerAtom* udta = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->FindChild("udta", true));
+ if (udta == NULL) return AP4_ERROR_INTERNAL;
+
+ // look for 'meta', and create if it does not exist ('meta' is a FULL atom)
+ AP4_ContainerAtom* meta = AP4_DYNAMIC_CAST(AP4_ContainerAtom, udta->FindChild("meta", true, true));
+ if (meta == NULL) return AP4_ERROR_INTERNAL;
+
+ // look for a 'hdlr' atom type 'mdir'
+ AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, meta->FindChild("hdlr"));
+ if (hdlr == NULL) {
+ hdlr = new AP4_HdlrAtom(AP4_HANDLER_TYPE_MDIR, "");
+ meta->AddChild(hdlr);
+ } else {
+ if (hdlr->GetHandlerType() != AP4_HANDLER_TYPE_MDIR) {
+ return AP4_ERROR_INVALID_FORMAT;
+ }
+ }
+
+ // get/create the list of entries
+ AP4_ContainerAtom* ilst = AP4_DYNAMIC_CAST(AP4_ContainerAtom, meta->FindChild("ilst", true));
+ if (ilst == NULL) return AP4_ERROR_INTERNAL;
+
+ // look if there is already a container for this entry
+ AP4_ContainerAtom* existing = FindInIlst(ilst);
+ if (existing == NULL) {
+ // just add the one we have
+ ilst->AddChild(entry_atom);
+ } else {
+ // add the entry's data to the existing entry
+ AP4_DataAtom* data_atom = AP4_DYNAMIC_CAST(AP4_DataAtom, entry_atom->GetChild(AP4_ATOM_TYPE_DATA));
+ if (data_atom == NULL) return AP4_ERROR_INTERNAL;
+ entry_atom->RemoveChild(data_atom);
+ existing->AddChild(data_atom, index);
+ delete entry_atom;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::AddToFileDcf
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Entry::AddToFileDcf(AP4_File& file, AP4_Ordinal index)
+{
+ // check that we have a correct entry
+ if (m_Value == NULL) return AP4_ERROR_INVALID_STATE;
+
+ // look for 'odrm/odhe'
+ AP4_ContainerAtom* odhe = AP4_DYNAMIC_CAST(AP4_ContainerAtom, file.FindChild("odrm/odhe"));
+ if (odhe == NULL) return AP4_ERROR_NO_SUCH_ITEM;
+
+ // get/create the list of entries
+ AP4_ContainerAtom* udta = AP4_DYNAMIC_CAST(AP4_ContainerAtom, odhe->FindChild("udta", true));
+ if (udta == NULL) return AP4_ERROR_INTERNAL;
+
+ // convert the entry into an atom
+ AP4_Atom* data_atom;
+ AP4_Result result = ToAtom(data_atom);
+ if (AP4_FAILED(result)) return result;
+
+ // add the entry's data to the container
+ return udta->AddChild(data_atom, index);
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::AddToFile
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Entry::AddToFile(AP4_File& file, AP4_Ordinal index)
+{
+ // check that we have a correct entry
+ if (m_Value == NULL) return AP4_ERROR_INVALID_STATE;
+
+ // check the namespace of the key to know where to add the atom
+ if (m_Key.GetNamespace() == "meta") {
+ return AddToFileIlst(file, index);
+ } else if (m_Key.GetNamespace() == "dcf") {
+ return AddToFileDcf(file, index);
+ } else {
+ // custom namespace
+ return AddToFileIlst(file, index);
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::RemoveFromFileIlst
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Entry::RemoveFromFileIlst(AP4_File& file, AP4_Ordinal index)
+{
+ // look for the 'moov'
+ AP4_Movie* movie = file.GetMovie();
+ if (movie == NULL) return AP4_ERROR_INVALID_FORMAT;
+ AP4_MoovAtom* moov = movie->GetMoovAtom();
+ if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
+
+ // look for 'udta/meta/ilst'
+ AP4_ContainerAtom* ilst = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moov->FindChild("udta/meta/ilst"));
+ if (ilst == NULL) return AP4_ERROR_NO_SUCH_ITEM;
+
+ // look if there is already a container for this entry
+ AP4_ContainerAtom* existing = FindInIlst(ilst);
+ if (existing == NULL) return AP4_ERROR_NO_SUCH_ITEM;
+
+ // remove the data atom in the entry
+ AP4_Result result = existing->DeleteChild(AP4_ATOM_TYPE_DATA, index);
+ if (AP4_FAILED(result)) return result;
+
+ // if the entry is empty, remove it
+ if (existing->GetChildren().ItemCount() == 0) {
+ ilst->RemoveChild(existing);
+ delete existing;
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::RemoveFromFileDcf
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Entry::RemoveFromFileDcf(AP4_File& file, AP4_Ordinal index)
+{
+ // look for 'odrm/odhe/udta'
+ AP4_ContainerAtom* udta = AP4_DYNAMIC_CAST(AP4_ContainerAtom, file.FindChild("odrm/odhe/udta"));
+ if (udta == NULL) return AP4_ERROR_NO_SUCH_ITEM;
+
+ // remove the data atom in the entry
+ AP4_UI32 type = AP4_BytesToUInt32BE((const unsigned char*)m_Key.GetName().GetChars());
+ AP4_Result result = udta->DeleteChild(type, index);
+ if (AP4_FAILED(result)) return result;
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaData::Entry::RemoveFromFile
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaData::Entry::RemoveFromFile(AP4_File& file, AP4_Ordinal index)
+{
+ // check the namespace of the key to know where to add the atom
+ if (m_Key.GetNamespace() == "meta") {
+ return RemoveFromFileIlst(file, index);
+ } else if (m_Key.GetNamespace() == "dcf") {
+ return RemoveFromFileDcf(file, index);
+ } else {
+ // unsupported namespace
+ return AP4_ERROR_NOT_SUPPORTED;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_StringMetaDataValue::ToString
++---------------------------------------------------------------------*/
+AP4_String
+AP4_StringMetaDataValue::ToString() const
+{
+ return m_Value;
+}
+
+/*----------------------------------------------------------------------
+| AP4_StringMetaDataValue::ToBytes
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_StringMetaDataValue::ToBytes(AP4_DataBuffer& /* bytes */) const
+{
+ return AP4_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+| AP4_StringMetaDataValue::ToInteger
++---------------------------------------------------------------------*/
+long
+AP4_StringMetaDataValue::ToInteger() const
+{
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IntegerMetaDataValue::ToString
++---------------------------------------------------------------------*/
+AP4_String
+AP4_IntegerMetaDataValue::ToString() const
+{
+ char value[16];
+ AP4_FormatString(value, sizeof(value), "%ld", m_Value);
+ return AP4_String(value);
+}
+
+/*----------------------------------------------------------------------
+| AP4_IntegerMetaDataValue::ToBytes
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_IntegerMetaDataValue::ToBytes(AP4_DataBuffer& /* bytes */) const
+{
+ return AP4_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+| AP4_IntegerMetaDataValue::ToInteger
++---------------------------------------------------------------------*/
+long
+AP4_IntegerMetaDataValue::ToInteger() const
+{
+ return m_Value;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BinaryMetaDataValue::ToString
++---------------------------------------------------------------------*/
+AP4_String
+AP4_BinaryMetaDataValue::ToString() const
+{
+ return AP4_String(); // not supported
+}
+
+/*----------------------------------------------------------------------
+| AP4_BinaryMetaDataValue::ToBytes
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_BinaryMetaDataValue::ToBytes(AP4_DataBuffer& bytes) const
+{
+ bytes.SetDataSize(m_Value.GetDataSize());
+ AP4_CopyMemory(bytes.UseData(), m_Value.GetData(), m_Value.GetDataSize());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_BinaryMetaDataValue::ToInteger
++---------------------------------------------------------------------*/
+long
+AP4_BinaryMetaDataValue::ToInteger() const
+{
+ return 0; // NOT SUPPORTED
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomMetaDataValue::AP4_AtomMetaDataValue
++---------------------------------------------------------------------*/
+AP4_AtomMetaDataValue::AP4_AtomMetaDataValue(AP4_DataAtom* atom,
+ AP4_UI32 parent_type) :
+ Value(atom->GetValueType()),
+ m_DataAtom(atom)
+{
+ switch (parent_type) {
+ case AP4_ATOM_TYPE_GNRE:
+ m_Meaning = MEANING_ID3_GENRE;
+ break;
+
+ case AP4_ATOM_TYPE_CPIL:
+ m_Meaning = MEANING_BOOLEAN;
+ break;
+
+ case AP4_ATOM_TYPE_PGAP:
+ case AP4_ATOM_TYPE_PCST:
+ m_Meaning = MEANING_BOOLEAN;
+ break;
+
+ case AP4_ATOM_TYPE_STIK:
+ m_Meaning = MEANING_FILE_KIND;
+ break;
+
+ case AP4_ATOM_TYPE_PURL:
+ case AP4_ATOM_TYPE_EGID:
+ m_Meaning = MEANING_BINARY_ENCODED_CHARS;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomMetaDataValue::ToString
++---------------------------------------------------------------------*/
+AP4_String
+AP4_AtomMetaDataValue::ToString() const
+{
+ char string[256] = "";
+
+ AP4_MetaData::Value::Type value_type = m_DataAtom->GetValueType();
+ switch (AP4_MetaData::Value::MapTypeToCategory(value_type)) {
+ case AP4_MetaData::Value::TYPE_CATEGORY_INTEGER:
+ {
+ long value;
+ if (AP4_SUCCEEDED(m_DataAtom->LoadInteger(value))) {
+ if (m_Meaning == MEANING_BOOLEAN) {
+ if (value) {
+ return "True";
+ } else {
+ return "False";
+ }
+ } else if (m_Meaning == MEANING_FILE_KIND) {
+ if (value >= 0 && ((unsigned int)value) <= sizeof(Ap4StikNames)/sizeof(Ap4StikNames[0])) {
+ AP4_FormatString(string, sizeof(string), "(%ld) %s", value, Ap4StikNames[value]);
+ } else {
+ return "Unknown";
+ }
+ } else {
+ AP4_FormatString(string, sizeof(string), "%ld", value);
+ }
+ }
+ return AP4_String((const char*)string);
+ break;
+ }
+
+ case AP4_MetaData::Value::TYPE_CATEGORY_STRING:
+ {
+ AP4_String* category_string;
+ if (AP4_SUCCEEDED(m_DataAtom->LoadString(category_string))) {
+ AP4_String result(*category_string);
+ delete category_string;
+ return result;
+ }
+ break;
+ }
+
+ case AP4_MetaData::Value::TYPE_CATEGORY_BINARY:
+ {
+ AP4_DataBuffer data;
+ if (AP4_SUCCEEDED(m_DataAtom->LoadBytes(data))) {
+ if (m_Meaning == MEANING_ID3_GENRE && data.GetDataSize() == 2) {
+ unsigned int genre = (data.GetData()[0])*256+data.GetData()[1];
+ if (genre >= 1 && genre <= sizeof(Ap4Id3Genres)/sizeof(Ap4Id3Genres[0])) {
+ AP4_FormatString(string, sizeof(string), "(%d) %s", genre, Ap4Id3Genres[genre-1]);
+ return AP4_String((const char*)string);
+ } else {
+ return "Unknown";
+ }
+ } else if (m_Meaning == MEANING_BINARY_ENCODED_CHARS) {
+ AP4_String result;
+ result.Assign((const char*)data.GetData(), data.GetDataSize());
+ return result;
+ } else {
+ unsigned int dump_length = data.GetDataSize();
+ bool truncate = false;
+ if (dump_length > 16) {
+ dump_length = 16;
+ truncate = true;
+ }
+ char* out = string;
+ for (unsigned int i=0; i<dump_length; i++) {
+ AP4_FormatString(out, sizeof(string)-(out-string), "%02x ", data.GetData()[i]);
+ out += 3;
+ }
+ if (truncate) {
+ *out++='.'; *out++='.'; *out++='.'; *out++=' ';
+ }
+ AP4_FormatString(out, sizeof(string)-(out-string), "[%ld bytes]", data.GetDataSize());
+ }
+ }
+ return AP4_String(string);
+ }
+ default:
+ return AP4_String();
+ }
+
+ return AP4_String();
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomMetaDataValue::ToBytes
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_AtomMetaDataValue::ToBytes(AP4_DataBuffer& bytes) const
+{
+ return m_DataAtom->LoadBytes(bytes);
+}
+
+/*----------------------------------------------------------------------
+| AP4_AtomMetaDataValue::ToInteger
++---------------------------------------------------------------------*/
+long
+AP4_AtomMetaDataValue::ToInteger() const
+{
+ long value;
+ if (AP4_SUCCEEDED(m_DataAtom->LoadInteger(value))) {
+ return value;
+ } else {
+ return 0;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::AP4_DataAtom
++---------------------------------------------------------------------*/
+AP4_DataAtom::AP4_DataAtom(const AP4_MetaData::Value& value) :
+ AP4_Atom(AP4_ATOM_TYPE_DATA, AP4_ATOM_HEADER_SIZE),
+ m_DataType(DATA_TYPE_BINARY)
+{
+ AP4_MemoryByteStream* memory = new AP4_MemoryByteStream(256);
+ AP4_Size payload_size = 8;
+ m_Source = memory;
+
+ switch (value.GetType()) {
+ case AP4_MetaData::Value::TYPE_STRING_UTF_8: {
+ m_DataType = DATA_TYPE_STRING_UTF_8;
+ AP4_String string_value = value.ToString();
+ if (string_value.GetLength()) {
+ memory->Write(string_value.GetChars(), string_value.GetLength());
+ }
+ payload_size += string_value.GetLength();
+ break;
+ }
+
+ case AP4_MetaData::Value::TYPE_INT_08_BE: {
+ m_DataType = DATA_TYPE_SIGNED_INT_BE;
+ AP4_UI08 int_value = (AP4_UI08)value.ToInteger();
+ memory->Write(&int_value, 1);
+ payload_size += 1;
+ break;
+ }
+
+ case AP4_MetaData::Value::TYPE_INT_16_BE: {
+ m_DataType = DATA_TYPE_SIGNED_INT_BE;
+ AP4_UI16 int_value = (AP4_UI16)value.ToInteger();
+ memory->Write(&int_value, 2);
+ payload_size += 2;
+ break;
+ }
+
+ case AP4_MetaData::Value::TYPE_INT_32_BE: {
+ m_DataType = DATA_TYPE_SIGNED_INT_BE;
+ AP4_UI32 int_value = (AP4_UI32)value.ToInteger();
+ memory->Write(&int_value, 4);
+ payload_size += 4;
+ break;
+ }
+
+ case AP4_MetaData::Value::TYPE_JPEG:
+ m_DataType = DATA_TYPE_JPEG;
+ // FALLTHROUGH
+ case AP4_MetaData::Value::TYPE_GIF:
+ if (m_DataType == DATA_TYPE_BINARY) m_DataType = DATA_TYPE_GIF;
+ // FALLTHROUGH
+ case AP4_MetaData::Value::TYPE_BINARY: {
+ AP4_DataBuffer buffer;
+ value.ToBytes(buffer);
+ if (buffer.GetDataSize()) {
+ memory->Write(buffer.GetData(), buffer.GetDataSize());
+ }
+ payload_size += buffer.GetDataSize();
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ const AP4_String& language = value.GetLanguage();
+ if (language == "en") {
+ m_DataLang = LANGUAGE_ENGLISH;
+ } else {
+ // default
+ m_DataLang = LANGUAGE_ENGLISH;
+ }
+
+ m_Size32 += payload_size;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::AP4_DataAtom
++---------------------------------------------------------------------*/
+AP4_DataAtom::AP4_DataAtom(AP4_UI32 size, AP4_ByteStream& stream) :
+ AP4_Atom(AP4_ATOM_TYPE_DATA, size)
+{
+ if (size < AP4_ATOM_HEADER_SIZE+8) return;
+
+ AP4_UI32 i;
+ stream.ReadUI32(i); m_DataType = (DataType)i;
+ stream.ReadUI32(i); m_DataLang = (DataLang)i;
+
+ // the stream for the data is a substream of this source
+ AP4_Position data_offset;
+ stream.Tell(data_offset);
+ AP4_Size data_size = size-AP4_ATOM_HEADER_SIZE-8;
+ m_Source = new AP4_SubStream(stream, data_offset, data_size);
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::~AP4_DataAtom
++---------------------------------------------------------------------*/
+AP4_DataAtom::~AP4_DataAtom()
+{
+ delete(m_Source);
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::GetValueType
++---------------------------------------------------------------------*/
+AP4_MetaData::Value::Type
+AP4_DataAtom::GetValueType()
+{
+ switch (m_DataType) {
+ case DATA_TYPE_BINARY:
+ return AP4_MetaData::Value::TYPE_BINARY;
+
+ case DATA_TYPE_SIGNED_INT_BE:
+ switch (m_Size32-16) {
+ case 1: return AP4_MetaData::Value::TYPE_INT_08_BE;
+ case 2: return AP4_MetaData::Value::TYPE_INT_16_BE;
+ case 4: return AP4_MetaData::Value::TYPE_INT_32_BE;
+ default: return AP4_MetaData::Value::TYPE_BINARY;
+ }
+ break;
+
+ case DATA_TYPE_STRING_UTF_8:
+ return AP4_MetaData::Value::TYPE_STRING_UTF_8;
+
+ case DATA_TYPE_STRING_UTF_16:
+ return AP4_MetaData::Value::TYPE_STRING_UTF_16;
+
+ case DATA_TYPE_STRING_PASCAL:
+ return AP4_MetaData::Value::TYPE_STRING_PASCAL;
+
+ case DATA_TYPE_GIF:
+ return AP4_MetaData::Value::TYPE_GIF;
+
+ case DATA_TYPE_JPEG:
+ return AP4_MetaData::Value::TYPE_JPEG;
+
+ default:
+ return AP4_MetaData::Value::TYPE_BINARY;
+ }
+
+ return AP4_MetaData::Value::TYPE_BINARY;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataAtom::WriteFields(AP4_ByteStream& stream)
+{
+ stream.WriteUI32(m_DataType);
+ stream.WriteUI32(m_DataLang);
+ if (m_Source) {
+ AP4_LargeSize size = 0;
+ m_Source->GetSize(size);
+ m_Source->Seek(0);
+ m_Source->CopyTo(stream, size);
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("type", m_DataType);
+ inspector.AddField("lang", m_DataLang);
+ if (m_DataType == DATA_TYPE_STRING_UTF_8) {
+ AP4_String* str;
+ if (AP4_SUCCEEDED(LoadString(str))) {
+ inspector.AddField("value", str->GetChars());
+ delete str;
+ }
+ } else if (m_DataType == DATA_TYPE_SIGNED_INT_BE) {
+ long value;
+ if (AP4_SUCCEEDED(LoadInteger(value))) {
+ inspector.AddField("value", value);
+ }
+ }
+
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::LoadString
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataAtom::LoadString(AP4_String*& string)
+{
+ if (m_Source == NULL) {
+ string = new AP4_String();
+ return AP4_SUCCESS;
+ } else {
+ // create a string with enough capactiy for the data
+ AP4_LargeSize size = 0;
+ m_Source->GetSize(size);
+ if (size > AP4_DATA_ATOM_MAX_SIZE) return AP4_ERROR_OUT_OF_RANGE;
+ string = new AP4_String((AP4_Size)size);
+
+ // read from the start of the stream
+ m_Source->Seek(0);
+ AP4_Result result = m_Source->Read(string->UseChars(), (AP4_Size)size);
+ if (AP4_FAILED(result)) {
+ delete string;
+ string = NULL;
+ }
+
+ return result;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::LoadBytes
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataAtom::LoadBytes(AP4_DataBuffer& bytes)
+{
+ if (m_Source == NULL) {
+ bytes.SetDataSize(0);
+ return AP4_SUCCESS;
+ }
+ AP4_LargeSize size = 0;
+ m_Source->GetSize(size);
+ if (size > AP4_DATA_ATOM_MAX_SIZE) return AP4_ERROR_OUT_OF_RANGE;
+ bytes.SetDataSize((AP4_Size)size);
+ m_Source->Seek(0);
+ AP4_Result result = m_Source->Read(bytes.UseData(), (AP4_Size)size);
+ if (AP4_FAILED(result)) {
+ bytes.SetDataSize(0);
+ }
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DataAtom::LoadInteger
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DataAtom::LoadInteger(long& value)
+{
+ AP4_Result result = AP4_FAILURE;
+ value = 0;
+ if (m_Source == NULL) return AP4_SUCCESS;
+ AP4_LargeSize size = 0;
+ m_Source->GetSize(size);
+ if (size > 4) {
+ return AP4_ERROR_OUT_OF_RANGE;
+ }
+ unsigned char bytes[4];
+ m_Source->Seek(0);
+ m_Source->Read(bytes, (AP4_Size)size);
+ result = AP4_SUCCESS;
+ switch (size) {
+ case 1: value = bytes[0]; break;
+ case 2: value = AP4_BytesToInt16BE(bytes); break;
+ case 4: value = AP4_BytesToInt32BE(bytes); break;
+ default: value = 0; result = AP4_ERROR_INVALID_FORMAT; break;
+ }
+ return result;
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaDataStringAtom::AP4_MetaDataStringAtom
++---------------------------------------------------------------------*/
+AP4_MetaDataStringAtom::AP4_MetaDataStringAtom(Type type, const char* value) :
+ AP4_Atom(type, AP4_ATOM_HEADER_SIZE),
+ m_Value(value)
+{
+ m_Size32 += 4+m_Value.GetLength();
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaDataStringAtom::AP4_MetaDataStringAtom
++---------------------------------------------------------------------*/
+AP4_MetaDataStringAtom::AP4_MetaDataStringAtom(Type type, AP4_UI32 size, AP4_ByteStream& stream) :
+ AP4_Atom(type, size),
+ m_Value((AP4_Size)(size-AP4_ATOM_HEADER_SIZE-4))
+{
+ stream.ReadUI32(m_Reserved);
+ stream.Read(m_Value.UseChars(), m_Value.GetLength());
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaDataStringAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaDataStringAtom::WriteFields(AP4_ByteStream& stream)
+{
+ stream.WriteUI32(m_Reserved);
+ return stream.Write(m_Value.GetChars(), m_Value.GetLength());
+}
+
+/*----------------------------------------------------------------------
+| AP4_MetaDataStringAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_MetaDataStringAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("value", m_Value.GetChars());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_3GppLocalizedStringAtom::Create
++---------------------------------------------------------------------*/
+AP4_3GppLocalizedStringAtom*
+AP4_3GppLocalizedStringAtom::Create(Type type, AP4_UI32 size, AP4_ByteStream& stream)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version != 0) return NULL;
+ return new AP4_3GppLocalizedStringAtom(type, size, version, flags, stream);
+}
+
+/*----------------------------------------------------------------------
+| AP4_3GppLocalizedStringAtom::AP4_3GppLocalizedStringAtom
++---------------------------------------------------------------------*/
+AP4_3GppLocalizedStringAtom::AP4_3GppLocalizedStringAtom(Type type,
+ const char* language,
+ const char* value) :
+ AP4_Atom(type, AP4_FULL_ATOM_HEADER_SIZE+2, 0, 0),
+ m_Value(value)
+{
+ m_Language[0] = language[0];
+ m_Language[1] = language[1];
+ m_Language[2] = language[2];
+ m_Language[3] = language[3];
+
+ m_Size32 += m_Value.GetLength()+1;
+}
+
+/*----------------------------------------------------------------------
+| AP4_3GppLocalizedStringAtom::AP4_3GppLocalizedStringAtom
++---------------------------------------------------------------------*/
+AP4_3GppLocalizedStringAtom::AP4_3GppLocalizedStringAtom(Type type,
+ AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream) :
+ AP4_Atom(type, size, version, flags)
+{
+ // read the language code
+ AP4_UI16 packed_language;
+ stream.ReadUI16(packed_language);
+ m_Language[0] = 0x60+((packed_language>>10)&0x1F);
+ m_Language[1] = 0x60+((packed_language>> 5)&0x1F);
+ m_Language[2] = 0x60+((packed_language )&0x1F);
+ m_Language[3] = '\0';
+
+ // read the value (should be a NULL-terminated string, but we'll
+ // allow for strings that are not terminated)
+ if (size > AP4_FULL_ATOM_HEADER_SIZE+2) {
+ AP4_UI32 value_size = size-(AP4_FULL_ATOM_HEADER_SIZE+2);
+ char* value = new char[value_size];
+ stream.Read(value, value_size);
+ m_Value.Assign(value, value_size);
+ delete[] value;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_3GppLocalizedStringAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_3GppLocalizedStringAtom::WriteFields(AP4_ByteStream& stream)
+{
+ AP4_UI16 packed_language = ((m_Language[0]-0x60)<<10) |
+ ((m_Language[1]-0x60)<< 5) |
+ ((m_Language[2]-0x60));
+ stream.WriteUI16(packed_language);
+ AP4_Size payload_size = (AP4_UI32)GetSize()-GetHeaderSize();
+ if (payload_size < 2) return AP4_ERROR_INVALID_FORMAT;
+ AP4_Size value_size = m_Value.GetLength()+1;
+ if (value_size > payload_size-2) {
+ value_size = payload_size-2;
+ }
+ stream.Write(m_Value.GetChars(), value_size);
+ for (unsigned int i=value_size; i<payload_size-2; i++) {
+ stream.WriteUI08(0);
+ }
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_3GppLocalizedStringAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_3GppLocalizedStringAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("language", GetLanguage());
+ inspector.AddField("value", m_Value.GetChars());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfStringAtom::Create
++---------------------------------------------------------------------*/
+AP4_DcfStringAtom*
+AP4_DcfStringAtom::Create(Type type, AP4_UI32 size, AP4_ByteStream& stream)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version != 0) return NULL;
+ return new AP4_DcfStringAtom(type, size, version, flags, stream);
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfStringAtom::AP4_DcfStringAtom
++---------------------------------------------------------------------*/
+AP4_DcfStringAtom::AP4_DcfStringAtom(Type type, const char* value) :
+ AP4_Atom(type, AP4_FULL_ATOM_HEADER_SIZE, 0, 0),
+ m_Value(value)
+{
+ m_Size32 += m_Value.GetLength();
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfStringAtom::AP4_DcfStringAtom
++---------------------------------------------------------------------*/
+AP4_DcfStringAtom::AP4_DcfStringAtom(Type type,
+ AP4_UI32 size,
+ AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream) :
+ AP4_Atom(type, size, version, flags)
+{
+ if (size > AP4_FULL_ATOM_HEADER_SIZE) {
+ AP4_UI32 value_size = size-(AP4_FULL_ATOM_HEADER_SIZE);
+ char* value = new char[value_size];
+ stream.Read(value, value_size);
+ m_Value.Assign(value, value_size);
+ delete[] value;
+ }
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfStringAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DcfStringAtom::WriteFields(AP4_ByteStream& stream)
+{
+ if (m_Value.GetLength()) stream.Write(m_Value.GetChars(), m_Value.GetLength());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfStringAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DcfStringAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("value", m_Value.GetChars());
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfdAtom::Create
++---------------------------------------------------------------------*/
+AP4_DcfdAtom*
+AP4_DcfdAtom::Create(AP4_UI32 size, AP4_ByteStream& stream)
+{
+ AP4_UI32 version;
+ AP4_UI32 flags;
+ if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL;
+ if (version != 0) return NULL;
+ if (size != AP4_FULL_ATOM_HEADER_SIZE+4) return NULL;
+ return new AP4_DcfdAtom(version, flags, stream);
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfdAtom::AP4_DcfdAtom
++---------------------------------------------------------------------*/
+AP4_DcfdAtom::AP4_DcfdAtom(AP4_UI32 version,
+ AP4_UI32 flags,
+ AP4_ByteStream& stream) :
+ AP4_Atom(AP4_ATOM_TYPE_DCFD, AP4_FULL_ATOM_HEADER_SIZE+4, version, flags)
+{
+ stream.ReadUI32(m_Duration);
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfdAtom::AP4_DcfdAtom
++---------------------------------------------------------------------*/
+AP4_DcfdAtom::AP4_DcfdAtom(AP4_UI32 duration) :
+ AP4_Atom(AP4_ATOM_TYPE_DCFD, AP4_FULL_ATOM_HEADER_SIZE+4, 0, 0),
+ m_Duration(duration)
+{
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfdAtom::WriteFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DcfdAtom::WriteFields(AP4_ByteStream& stream)
+{
+ stream.WriteUI32(m_Duration);
+ return AP4_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| AP4_DcfdAtom::InspectFields
++---------------------------------------------------------------------*/
+AP4_Result
+AP4_DcfdAtom::InspectFields(AP4_AtomInspector& inspector)
+{
+ inspector.AddField("duration", m_Duration);
+ return AP4_SUCCESS;
+}
diff --git a/src/filters/parser/MP4Splitter/AP4/Source/MetaData/Ap4MetaData.h b/src/filters/parser/MP4Splitter/AP4/Source/MetaData/Ap4MetaData.h new file mode 100644 index 000000000..491365f11 --- /dev/null +++ b/src/filters/parser/MP4Splitter/AP4/Source/MetaData/Ap4MetaData.h @@ -0,0 +1,576 @@ +/***************************************************************** +| +| AP4 - MetaData +| +| Copyright 2002-2008 Axiomatic Systems, LLC +| +| +| This file is part of Bento4/AP4 (MP4 Atom Processing Library). +| +| Unless you have obtained Bento4 under a difference license, +| this version of Bento4 is Bento4|GPL. +| Bento4|GPL is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2, or (at your option) +| any later version. +| +| Bento4|GPL is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with Bento4|GPL; see the file COPYING. If not, write to the +| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +| 02111-1307, USA. +| +****************************************************************/ + +#ifndef _AP4_META_DATA_H_ +#define _AP4_META_DATA_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Ap4Atom.h" +#include "Ap4AtomFactory.h" +#include "Ap4String.h" +#include "Ap4Array.h" +#include "Ap4List.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_File; +class AP4_MoovAtom; +class AP4_DataBuffer; +class AP4_ContainerAtom; +class AP4_DataAtom; +class AP4_3GppLocalizedStringAtom; +class AP4_DcfStringAtom; +class AP4_DcfdAtom; + +/*---------------------------------------------------------------------- +| metadata keys ++---------------------------------------------------------------------*/ +const AP4_Atom::Type AP4_ATOM_TYPE_DATA = AP4_ATOM_TYPE('d','a','t','a'); // data +const AP4_Atom::Type AP4_ATOM_TYPE_MEAN = AP4_ATOM_TYPE('m','e','a','n'); // namespace +const AP4_Atom::Type AP4_ATOM_TYPE_NAME = AP4_ATOM_TYPE('n','a','m','e'); // name +const AP4_Atom::Type AP4_ATOM_TYPE_dddd = AP4_ATOM_TYPE('-','-','-','-'); // free form +const AP4_Atom::Type AP4_ATOM_TYPE_cNAM = AP4_ATOM_TYPE(0xA9,'n','a','m'); // name +const AP4_Atom::Type AP4_ATOM_TYPE_cART = AP4_ATOM_TYPE(0xA9,'A','R','T'); // artist +const AP4_Atom::Type AP4_ATOM_TYPE_cCOM = AP4_ATOM_TYPE(0xA9,'c','o','m'); // composer +const AP4_Atom::Type AP4_ATOM_TYPE_cWRT = AP4_ATOM_TYPE(0xA9,'w','r','t'); // writer +const AP4_Atom::Type AP4_ATOM_TYPE_cALB = AP4_ATOM_TYPE(0xA9,'a','l','b'); // album +const AP4_Atom::Type AP4_ATOM_TYPE_cGEN = AP4_ATOM_TYPE(0xA9,'g','e','n'); // genre +const AP4_Atom::Type AP4_ATOM_TYPE_cGRP = AP4_ATOM_TYPE(0xA9,'g','r','p'); // group +const AP4_Atom::Type AP4_ATOM_TYPE_cDAY = AP4_ATOM_TYPE(0xA9,'d','a','y'); // date +const AP4_Atom::Type AP4_ATOM_TYPE_cTOO = AP4_ATOM_TYPE(0xA9,'t','o','o'); // tool +const AP4_Atom::Type AP4_ATOM_TYPE_cCMT = AP4_ATOM_TYPE(0xA9,'c','m','t'); // comment +const AP4_Atom::Type AP4_ATOM_TYPE_cLYR = AP4_ATOM_TYPE(0xA9,'l','y','r'); // lyrics +const AP4_Atom::Type AP4_ATOM_TYPE_TRKN = AP4_ATOM_TYPE('t','r','k','n'); // track# +const AP4_Atom::Type AP4_ATOM_TYPE_DISK = AP4_ATOM_TYPE('d','i','s','k'); // disk# +const AP4_Atom::Type AP4_ATOM_TYPE_COVR = AP4_ATOM_TYPE('c','o','v','r'); // cover art +const AP4_Atom::Type AP4_ATOM_TYPE_DESC = AP4_ATOM_TYPE('d','e','s','c'); // description +const AP4_Atom::Type AP4_ATOM_TYPE_CPIL = AP4_ATOM_TYPE('c','p','i','l'); // compilation? +const AP4_Atom::Type AP4_ATOM_TYPE_TMPO = AP4_ATOM_TYPE('t','m','p','o'); // tempo +const AP4_Atom::Type AP4_ATOM_TYPE_apID = AP4_ATOM_TYPE('a','p','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_cnID = AP4_ATOM_TYPE('c','n','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_cmID = AP4_ATOM_TYPE('c','m','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_atID = AP4_ATOM_TYPE('a','t','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_plID = AP4_ATOM_TYPE('p','l','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_geID = AP4_ATOM_TYPE('g','e','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_sfID = AP4_ATOM_TYPE('s','f','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_akID = AP4_ATOM_TYPE('a','k','I','D'); +const AP4_Atom::Type AP4_ATOM_TYPE_aART = AP4_ATOM_TYPE('a','A','R','T'); +const AP4_Atom::Type AP4_ATOM_TYPE_TVNN = AP4_ATOM_TYPE('t','v','n','n'); // TV network +const AP4_Atom::Type AP4_ATOM_TYPE_TVSH = AP4_ATOM_TYPE('t','v','s','h'); // TV show +const AP4_Atom::Type AP4_ATOM_TYPE_TVEN = AP4_ATOM_TYPE('t','v','e','n'); // TV episode name +const AP4_Atom::Type AP4_ATOM_TYPE_TVSN = AP4_ATOM_TYPE('t','v','s','n'); // TV show season # +const AP4_Atom::Type AP4_ATOM_TYPE_TVES = AP4_ATOM_TYPE('t','v','e','s'); // TV show episode # +const AP4_Atom::Type AP4_ATOM_TYPE_STIK = AP4_ATOM_TYPE('s','t','i','k'); +const AP4_Atom::Type AP4_ATOM_TYPE_PCST = AP4_ATOM_TYPE('p','c','s','t'); // Podcast? +const AP4_Atom::Type AP4_ATOM_TYPE_PURD = AP4_ATOM_TYPE('p','u','r','d'); // +const AP4_Atom::Type AP4_ATOM_TYPE_PURL = AP4_ATOM_TYPE('p','u','r','l'); // Podcast URL (binary) +const AP4_Atom::Type AP4_ATOM_TYPE_EGID = AP4_ATOM_TYPE('e','g','i','d'); // +const AP4_Atom::Type AP4_ATOM_TYPE_PGAP = AP4_ATOM_TYPE('p','g','a','p'); // Gapless Playback +const AP4_Atom::Type AP4_ATOM_TYPE_CATG = AP4_ATOM_TYPE('c','a','t','g'); // Category +const AP4_Atom::Type AP4_ATOM_TYPE_KEYW = AP4_ATOM_TYPE('k','e','y','w'); // Keywords +const AP4_Atom::Type AP4_ATOM_TYPE_SONM = AP4_ATOM_TYPE('s','o','n','m'); // Sort-Order: Name +const AP4_Atom::Type AP4_ATOM_TYPE_SOAL = AP4_ATOM_TYPE('s','o','a','l'); // Sort-Order: Album +const AP4_Atom::Type AP4_ATOM_TYPE_SOAR = AP4_ATOM_TYPE('s','o','a','r'); // Sort-Order: Artist +const AP4_Atom::Type AP4_ATOM_TYPE_SOAA = AP4_ATOM_TYPE('s','o','a','a'); // Sort-Order: Album Artist +const AP4_Atom::Type AP4_ATOM_TYPE_SOCO = AP4_ATOM_TYPE('s','o','c','o'); // Sort-Order: Composer +const AP4_Atom::Type AP4_ATOM_TYPE_SOSN = AP4_ATOM_TYPE('s','o','s','n'); // Sort-Order: Show + +const AP4_Atom::Type AP4_ATOM_TYPE_TITL = AP4_ATOM_TYPE('t','i','t','l'); // 3GPP: title +const AP4_Atom::Type AP4_ATOM_TYPE_DSCP = AP4_ATOM_TYPE('d','s','c','p'); // 3GPP: description +const AP4_Atom::Type AP4_ATOM_TYPE_CPRT = AP4_ATOM_TYPE('c','p','r','t'); // 3GPP, ISO or ILST: copyright +const AP4_Atom::Type AP4_ATOM_TYPE_PERF = AP4_ATOM_TYPE('p','e','r','f'); // 3GPP: performer +const AP4_Atom::Type AP4_ATOM_TYPE_AUTH = AP4_ATOM_TYPE('a','u','t','h'); // 3GPP: author +const AP4_Atom::Type AP4_ATOM_TYPE_GNRE = AP4_ATOM_TYPE('g','n','r','e'); // 3GPP or ILST: genre (in 3GPP -> string, in ILST -> ID3v1 index + 1) +const AP4_Atom::Type AP4_ATOM_TYPE_RTNG = AP4_ATOM_TYPE('r','t','n','g'); // 3GPP or ILST: rating +const AP4_Atom::Type AP4_ATOM_TYPE_CLSF = AP4_ATOM_TYPE('c','l','s','f'); // 3GPP: classification +const AP4_Atom::Type AP4_ATOM_TYPE_KYWD = AP4_ATOM_TYPE('k','y','w','d'); // 3GPP: keywords +const AP4_Atom::Type AP4_ATOM_TYPE_LOCI = AP4_ATOM_TYPE('l','o','c','i'); // 3GPP: location information +const AP4_Atom::Type AP4_ATOM_TYPE_ALBM = AP4_ATOM_TYPE('a','l','b','m'); // 3GPP: album title and track number +const AP4_Atom::Type AP4_ATOM_TYPE_YRRC = AP4_ATOM_TYPE('y','r','r','c'); // 3GPP: recording year +const AP4_Atom::Type AP4_ATOM_TYPE_TSEL = AP4_ATOM_TYPE('t','s','e','l'); // 3GPP: track selection + +const AP4_Atom::Type AP4_ATOM_TYPE_ICNU = AP4_ATOM_TYPE('i','c','n','u'); // DCF: icon URI (OMA DCF 2.1) +const AP4_Atom::Type AP4_ATOM_TYPE_INFU = AP4_ATOM_TYPE('i','n','f','u'); // DCF: info URI (OMA DCF 2.1) +const AP4_Atom::Type AP4_ATOM_TYPE_CVRU = AP4_ATOM_TYPE('c','v','r','u'); // DCF: cover art URI (OMA DCF 2.1) +const AP4_Atom::Type AP4_ATOM_TYPE_LRCU = AP4_ATOM_TYPE('l','r','c','u'); // DCF: lyrics URI (OMA DCF 2.1) +const AP4_Atom::Type AP4_ATOM_TYPE_DCFD = AP4_ATOM_TYPE('d','c','f','D'); // DCF: duration (OMarlin) + +/*---------------------------------------------------------------------- +| AP4_MetaData ++---------------------------------------------------------------------*/ +class AP4_MetaData { +public: + class Key { + public: + // constructors + Key(const char* name, const char* ns) : + m_Name(name), m_Namespace(ns) {} + + // methods + const AP4_String& GetNamespace() const { return m_Namespace; } + const AP4_String& GetName() const { return m_Name; } + + private: + // members + const AP4_String m_Name; + const AP4_String m_Namespace; + }; + + class Value { + public: + // types + typedef enum { + TYPE_BINARY, + TYPE_STRING_UTF_8, + TYPE_STRING_UTF_16, + TYPE_STRING_PASCAL, + TYPE_GIF, + TYPE_JPEG, + TYPE_INT_08_BE, + TYPE_INT_16_BE, + TYPE_INT_32_BE, + TYPE_FLOAT_32_BE, + TYPE_FLOAT_64_BE + } Type; + + typedef enum { + TYPE_CATEGORY_STRING, + TYPE_CATEGORY_BINARY, + TYPE_CATEGORY_INTEGER, + TYPE_CATEGORY_FLOAT + } TypeCategory; + + typedef enum { + MEANING_UNKNOWN, + MEANING_ID3_GENRE, + MEANING_BOOLEAN, + MEANING_FILE_KIND, + MEANING_BINARY_ENCODED_CHARS + } Meaning; + + // destructor + virtual ~Value() {} + + // methods + Type GetType() const { return m_Type; } + TypeCategory GetTypeCategory() const; + Meaning GetMeaning() const { return m_Meaning; } + const AP4_String& GetLanguage() const { return m_Language; } + void SetLanguage(const char* language) { m_Language = language; } + virtual AP4_String ToString() const = 0; + virtual AP4_Result ToBytes(AP4_DataBuffer& bytes) const = 0; + virtual long ToInteger() const = 0; + + protected: + // class methods + static TypeCategory MapTypeToCategory(Type type); + + // constructor + Value(Type type, + Meaning meaning = MEANING_UNKNOWN, + const char* language = NULL) : + m_Type(type), m_Meaning(meaning), m_Language(language) {} + + // members + Type m_Type; + Meaning m_Meaning; + AP4_String m_Language; + }; + + class KeyInfo { + public: + // members + const char* name; + const char* description; + AP4_UI32 four_cc; + Value::Type value_type; + }; + + class Entry { + public: + // constructor + Entry(const char* name, const char* ns, Value* value) : + m_Key(name, ns), m_Value(value) {} + + // destructor + ~Entry() { delete m_Value; } + + // methods + AP4_Result AddToFile(AP4_File& file, AP4_Ordinal index = 0); + AP4_Result AddToFileIlst(AP4_File& file, AP4_Ordinal index = 0); + AP4_Result AddToFileDcf(AP4_File& file, AP4_Ordinal index = 0); + AP4_Result RemoveFromFile(AP4_File& file, AP4_Ordinal index); + AP4_Result RemoveFromFileIlst(AP4_File& file, AP4_Ordinal index); + AP4_Result RemoveFromFileDcf(AP4_File& file, AP4_Ordinal index); + AP4_ContainerAtom* FindInIlst(AP4_ContainerAtom* ilst) const; + AP4_Result ToAtom(AP4_Atom*& atom) const; + + // members + Key m_Key; + Value* m_Value; + }; + + // class members + static AP4_Array<KeyInfo> KeyInfos; + + // constructor + AP4_MetaData(AP4_File* file); + + // methods + AP4_Result ParseMoov(AP4_MoovAtom* moov); + AP4_Result ParseUdta(AP4_ContainerAtom* udta, const char* namespc); + + // destructor + ~AP4_MetaData(); + + // accessors + const AP4_List<Entry>& GetEntries() const { return m_Entries; } + + // methods + AP4_Result ResolveKeyName(AP4_Atom::Type atom_type, AP4_String& value); + AP4_Result AddIlstEntries(AP4_ContainerAtom* atom, const char* namespc); + AP4_Result Add3GppEntry(AP4_3GppLocalizedStringAtom* atom, const char* namespc); + AP4_Result AddDcfStringEntry(AP4_DcfStringAtom* atom, const char* namespc); + AP4_Result AddDcfdEntry(AP4_DcfdAtom* atom, const char* namespc); + +private: + // members + AP4_List<Entry> m_Entries; +}; + +/*---------------------------------------------------------------------- +| AP4_MetaDataAtomTypeHandler ++---------------------------------------------------------------------*/ +class AP4_MetaDataAtomTypeHandler : public AP4_AtomFactory::TypeHandler +{ +public: + // constructor + AP4_MetaDataAtomTypeHandler(AP4_AtomFactory* atom_factory) : + m_AtomFactory(atom_factory) {} + virtual AP4_Result CreateAtom(AP4_Atom::Type type, + AP4_UI32 size, + AP4_ByteStream& stream, + AP4_Atom::Type context, + AP4_Atom*& atom); + + // types + struct TypeList { + const AP4_Atom::Type* m_Types; + AP4_Size m_Size; + }; + + // class constants + static const AP4_Atom::Type IlstTypes[]; + static const TypeList IlstTypeList; + static const AP4_Atom::Type _3gppLocalizedStringTypes[]; + static const TypeList _3gppLocalizedStringTypeList; + static const AP4_Atom::Type _3gppOtherTypes[]; + static const TypeList _3gppOtherTypeList; + static const AP4_Atom::Type DcfStringTypes[]; + static const TypeList DcfStringTypeList; + + // class methods + static bool IsTypeInList(AP4_Atom::Type type, const TypeList& list); + +private: + // members + AP4_AtomFactory* m_AtomFactory; +}; + +/*---------------------------------------------------------------------- +| AP4_MetaDataTag ++---------------------------------------------------------------------*/ +class AP4_MetaDataTag +{ +public: + + // destructor + virtual ~AP4_MetaDataTag() {} + + // methods + virtual AP4_Result Write(AP4_ByteStream& stream); + virtual AP4_Result Inspect(AP4_AtomInspector& inspector); + +protected: + // constructor + AP4_MetaDataTag(AP4_UI32 data_type, + AP4_UI32 data_lang, + AP4_Size size, + AP4_ByteStream& stream); + +}; + +/*---------------------------------------------------------------------- +| AP4_3GppLocalizedStringAtom ++---------------------------------------------------------------------*/ +class AP4_3GppLocalizedStringAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_3GppLocalizedStringAtom, AP4_Atom) + + // factory method + static AP4_3GppLocalizedStringAtom* Create(Type type, AP4_UI32 size, AP4_ByteStream& stream); + + // constructor + AP4_3GppLocalizedStringAtom(Type type, const char* language, const char* value); + AP4_3GppLocalizedStringAtom(Type type, + AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // AP4_Atom methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // methods + const char* GetLanguage() const { return m_Language; } + const AP4_String& GetValue() const { return m_Value; } + +private: + // members + char m_Language[4]; + AP4_String m_Value; +}; + +/*---------------------------------------------------------------------- +| AP4_DcfStringAtom ++---------------------------------------------------------------------*/ +class AP4_DcfStringAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DcfStringAtom, AP4_Atom) + + // factory method + static AP4_DcfStringAtom* Create(Type type, AP4_UI32 size, AP4_ByteStream& stream); + + // constructor + AP4_DcfStringAtom(Type type, const char* value); + AP4_DcfStringAtom(Type type, + AP4_UI32 size, + AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + + // AP4_Atom methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // methods + const AP4_String& GetValue() const { return m_Value; } + +private: + // members + AP4_String m_Value; +}; + +/*---------------------------------------------------------------------- +| AP4_DcfdAtom ++---------------------------------------------------------------------*/ +class AP4_DcfdAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DcfdAtom, AP4_Atom) + + // factory method + static AP4_DcfdAtom* Create(AP4_UI32 size, AP4_ByteStream& stream); + + // constructors + AP4_DcfdAtom(AP4_UI32 version, + AP4_UI32 flags, + AP4_ByteStream& stream); + AP4_DcfdAtom(AP4_UI32 duration); + + // AP4_Atom methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // methods + AP4_UI32 GetDuration() const { return m_Duration; } + +private: + // members + AP4_UI32 m_Duration; +}; + +/*---------------------------------------------------------------------- +| AP4_MetaDataStringAtom ++---------------------------------------------------------------------*/ +class AP4_MetaDataStringAtom : public AP4_Atom +{ +public: + // constructors + AP4_MetaDataStringAtom(Type type, const char* value); + AP4_MetaDataStringAtom(Type type, AP4_UI32 size, AP4_ByteStream& stream); + + // AP4_Atom methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // methods + const AP4_String& GetValue() { return m_Value; } + +private: + // members + AP4_UI32 m_Reserved; + AP4_String m_Value; +}; + +/*---------------------------------------------------------------------- +| AP4_DataAtom ++---------------------------------------------------------------------*/ +class AP4_DataAtom : public AP4_Atom +{ +public: + AP4_IMPLEMENT_DYNAMIC_CAST_D(AP4_DataAtom, AP4_Atom) + + typedef enum { + DATA_TYPE_BINARY = 0, + DATA_TYPE_STRING_UTF_8 = 1, + DATA_TYPE_STRING_UTF_16 = 2, + DATA_TYPE_STRING_PASCAL = 3, + DATA_TYPE_GIF = 13, + DATA_TYPE_JPEG = 14, + DATA_TYPE_SIGNED_INT_BE = 21, /* the size of the integer is derived from the container size */ + DATA_TYPE_FLOAT_32_BE = 22, + DATA_TYPE_FLOAT_64_BE = 23 + } DataType; + + typedef enum { + LANGUAGE_ENGLISH = 0 + } DataLang; + + // constructors + AP4_DataAtom(const AP4_MetaData::Value& value); + AP4_DataAtom(AP4_UI32 size, AP4_ByteStream& stream); + + // destructor + ~AP4_DataAtom(); + + // AP4_Atom methods + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + + // accessors + DataType GetDataType() { return m_DataType; } + DataLang GetDataLang() { return m_DataLang; } + AP4_MetaData::Value::Type GetValueType(); + + // methods + AP4_Result LoadString(AP4_String*& string); + AP4_Result LoadBytes(AP4_DataBuffer& bytes); + AP4_Result LoadInteger(long& value); + +private: + // members + DataType m_DataType; + DataLang m_DataLang; + AP4_ByteStream* m_Source; +}; + +/*---------------------------------------------------------------------- +| AP4_StringMetaDataValue ++---------------------------------------------------------------------*/ +class AP4_StringMetaDataValue : public AP4_MetaData::Value { +public: + // constructor + AP4_StringMetaDataValue(const char* value, const char* language=NULL) : + Value(TYPE_STRING_UTF_8, MEANING_UNKNOWN, language), + m_Value(value) {} + + // AP4_MetaData::Value methods + virtual AP4_String ToString() const; + virtual AP4_Result ToBytes(AP4_DataBuffer& bytes) const; + virtual long ToInteger() const; + +private: + // members + AP4_String m_Value; +}; + +/*---------------------------------------------------------------------- +| AP4_IntegerMetaDataValue ++---------------------------------------------------------------------*/ +class AP4_IntegerMetaDataValue : public AP4_MetaData::Value { +public: + // constructor + AP4_IntegerMetaDataValue(Type type, long value) : + Value(type), m_Value(value) {} + + // AP4_MetaData::Value methods + virtual AP4_String ToString() const; + virtual AP4_Result ToBytes(AP4_DataBuffer& bytes) const; + virtual long ToInteger() const; + +private: + // members + long m_Value; +}; + +/*---------------------------------------------------------------------- +| AP4_BinaryMetaDataValue ++---------------------------------------------------------------------*/ +class AP4_BinaryMetaDataValue : public AP4_MetaData::Value { +public: + // constructor + AP4_BinaryMetaDataValue(Type type, const AP4_UI08* data, AP4_Size size) : + Value(type), m_Value(data, size) {} + + // AP4_MetaData::Value methods + virtual AP4_String ToString() const; + virtual AP4_Result ToBytes(AP4_DataBuffer& bytes) const; + virtual long ToInteger() const; + +private: + // members + AP4_DataBuffer m_Value; +}; + +/*---------------------------------------------------------------------- +| AP4_AtomMetaDataValue ++---------------------------------------------------------------------*/ +class AP4_AtomMetaDataValue : public AP4_MetaData::Value +{ +public: + // constructor + AP4_AtomMetaDataValue(AP4_DataAtom* data_atom, AP4_UI32 parent_type); + + // AP4_MetaData::Value methods + virtual AP4_String ToString() const; + virtual AP4_Result ToBytes(AP4_DataBuffer& bytes) const; + virtual long ToInteger() const; + +private: + // members + AP4_DataAtom* m_DataAtom; +}; + +#endif // _AP4_META_DATA_H_ |