/***************************************************************** | | 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 "Ap4SthdAtom.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_UI64 creation_time, AP4_UI64 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_UI16 layer, AP4_UI16 alternate_group, const AP4_SI32* matrix) : 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, layer, alternate_group, matrix); // 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; case AP4_HANDLER_TYPE_SUBT: minf_header = new AP4_SthdAtom(); 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")) != NULL) { AP4_StcoAtom* stco = AP4_DYNAMIC_CAST(AP4_StcoAtom, atom); if (stco == NULL) return AP4_ERROR_INVALID_FORMAT; return stco->AdjustChunkOffsets((int)delta); } else if ((atom = FindChild("mdia/minf/stbl/co64")) != NULL) { AP4_Co64Atom* co64 = AP4_DYNAMIC_CAST(AP4_Co64Atom, atom); if (co64 == NULL) return AP4_ERROR_INVALID_FORMAT; return co64->AdjustChunkOffsets(delta); } else { return AP4_ERROR_INVALID_STATE; } } /*---------------------------------------------------------------------- | AP4_TrakAtom::GetChunkOffsets +---------------------------------------------------------------------*/ AP4_Result AP4_TrakAtom::GetChunkOffsets(AP4_Array& chunk_offsets) { AP4_Atom* atom; if ((atom = FindChild("mdia/minf/stbl/stco")) != NULL) { 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; iGetChunkCount(); const AP4_UI64* co64_chunk_offsets = co64->GetChunkOffsets(); chunk_offsets.SetItemCount(co64_chunk_count); for (unsigned int i=0; i& chunk_offsets) { AP4_Atom* atom; if ((atom = FindChild("mdia/minf/stbl/stco")) != NULL) { 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; iGetChunkCount(); 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