Ap4Processor.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:10k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /*****************************************************************
  2. |
  3. |    AP4 - File Processor
  4. |
  5. |    Copyright 2003-2005 Gilles Boccon-Gibod & Julien Boeuf
  6. |
  7. |
  8. |    This file is part of Bento4/AP4 (MP4 Atom Processing Library).
  9. |
  10. |    Unless you have obtained Bento4 under a difference license,
  11. |    this version of Bento4 is Bento4|GPL.
  12. |    Bento4|GPL is free software; you can redistribute it and/or modify
  13. |    it under the terms of the GNU General Public License as published by
  14. |    the Free Software Foundation; either version 2, or (at your option)
  15. |    any later version.
  16. |
  17. |    Bento4|GPL is distributed in the hope that it will be useful,
  18. |    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. |    GNU General Public License for more details.
  21. |
  22. |    You should have received a copy of the GNU General Public License
  23. |    along with Bento4|GPL; see the file COPYING.  If not, write to the
  24. |    Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  25. |    02111-1307, USA.
  26. |
  27. ****************************************************************/
  28. /*----------------------------------------------------------------------
  29. |       includes
  30. +---------------------------------------------------------------------*/
  31. #include "Ap4Processor.h"
  32. #include "Ap4AtomSampleTable.h"
  33. #include "Ap4AtomFactory.h"
  34. #include "Ap4MoovAtom.h"
  35. #include "Ap4Array.h"
  36. #include "Ap4Debug.h"
  37. /*----------------------------------------------------------------------
  38. |       types
  39. +---------------------------------------------------------------------*/
  40. class AP4_SampleLocator {
  41. public:
  42.     AP4_SampleLocator() : 
  43.         m_TrakIndex(0), 
  44.         m_SampleTable(NULL), 
  45.         m_SampleIndex(0), 
  46.         m_Chunk(0) {}
  47.     AP4_Ordinal          m_TrakIndex;
  48.     AP4_AtomSampleTable* m_SampleTable;
  49.     AP4_Ordinal          m_SampleIndex;
  50.     AP4_Sample           m_Sample;
  51.     AP4_Ordinal          m_Chunk;
  52. };
  53. struct AP4_SampleCursor {
  54.     AP4_SampleLocator m_Locator;
  55. };
  56. /*----------------------------------------------------------------------
  57. |       AP4_Processor::Process
  58. +---------------------------------------------------------------------*/
  59. AP4_Result
  60. AP4_Processor::Process(AP4_ByteStream&  input, 
  61.                        AP4_ByteStream&  output,
  62.                        AP4_AtomFactory& atom_factory)
  63. {
  64.     // read all atoms 
  65.     AP4_AtomParent top_level;
  66.     AP4_Atom* atom;
  67.     while (AP4_SUCCEEDED(atom_factory.CreateAtomFromStream(input, atom))) {
  68.         top_level.AddChild(atom);
  69.     }
  70.     // remove the [mdat] and [free] atoms, keep a ref to [moov]
  71.     AP4_MoovAtom* moov = NULL;
  72.     AP4_List<AP4_Atom>::Item* atom_item = top_level.GetChildren().FirstItem();
  73.     while (atom_item) {
  74.         atom = atom_item->GetData();
  75.         AP4_List<AP4_Atom>::Item* next = atom_item->GetNext();
  76.         if (//atom->GetType() == AP4_ATOM_TYPE_FREE ||
  77.             atom->GetType() == AP4_ATOM_TYPE_MDAT) {
  78.             atom->Detach();
  79.             delete atom;
  80.         } else if (atom->GetType() == AP4_ATOM_TYPE_MOOV) {
  81.             moov = (AP4_MoovAtom*)atom;
  82.         }
  83.         atom_item = next;
  84.     }
  85.     // check that we have a moov atom
  86.     if (moov == NULL) return AP4_FAILURE;
  87.     // initialize the processor
  88.     AP4_Result result = Initialize(top_level);
  89.     if (AP4_FAILED(result)) return result;
  90.     // build an array of track sample cursors
  91.     AP4_List<AP4_TrakAtom>& trak_atoms = moov->GetTrakAtoms();
  92.     AP4_Cardinal track_count = trak_atoms.ItemCount();
  93.     AP4_SampleCursor* cursors = new AP4_SampleCursor[track_count];
  94.     TrackHandler** handlers = new TrackHandler*[track_count];
  95.     AP4_List<AP4_TrakAtom>::Item* item = trak_atoms.FirstItem();
  96.     unsigned int index = 0;
  97.     while (item) {
  98.         // create the track handler    // find the stsd atom
  99.         AP4_ContainerAtom* stbl = dynamic_cast<AP4_ContainerAtom*>(
  100.             item->GetData()->FindChild("mdia/minf/stbl"));
  101.         if (stbl == NULL) continue;
  102.         handlers[index] = CreateTrackHandler(item->GetData());
  103.         cursors[index].m_Locator.m_TrakIndex = index;
  104.         cursors[index].m_Locator.m_SampleTable = new AP4_AtomSampleTable(stbl, input);
  105.         cursors[index].m_Locator.m_SampleIndex = 0;
  106.         cursors[index].m_Locator.m_SampleTable->GetSample(0, cursors[index].m_Locator.m_Sample);
  107.         cursors[index].m_Locator.m_Chunk = 1;
  108.         index++;
  109.         item = item->GetNext();
  110.     }
  111.     // figure out the layout of the chunks
  112.     AP4_Array<AP4_SampleLocator> locators;
  113.     for (;;) {
  114.         // see which is the next sample to write
  115.         unsigned int min_offset = 0xFFFFFFFF;
  116.         int cursor = -1;
  117.         for (unsigned int i=0; i<track_count; i++) {
  118.             if (cursors[i].m_Locator.m_SampleTable &&
  119.                 cursors[i].m_Locator.m_Sample.GetOffset() <= min_offset) {
  120.                     min_offset = cursors[i].m_Locator.m_Sample.GetOffset();
  121.                     cursor = i;
  122.             }
  123.         }
  124.         // stop if all cursors are exhausted
  125.         if (cursor == -1) break;
  126.         // append this locator to the layout list
  127.         AP4_SampleLocator& locator = cursors[cursor].m_Locator;
  128.         locators.Append(locator);
  129.         //AP4_Debug("NEXT: track %d, sample %d:%d: offset=%d, size=%dn",
  130.         //    locator.m_TrakIndex, 
  131.         //    locator.m_Chunk,
  132.         //    locator.m_SampleIndex,
  133.         //    locator.m_Sample.GetOffset(),
  134.         //    locator.m_Sample.GetSize());
  135.         // move the cursor to the next sample
  136.         locator.m_SampleIndex++;
  137.         if (locator.m_SampleIndex == locator.m_SampleTable->GetSampleCount()) {
  138.             // mark this track as completed
  139.             locator.m_SampleTable = NULL;
  140.         } else {
  141.             // get the next sample info
  142.             locator.m_SampleTable->GetSample(locator.m_SampleIndex, 
  143.                 locator.m_Sample);
  144.             AP4_Ordinal skip, sdesc;
  145.             locator.m_SampleTable->GetChunkForSample(locator.m_SampleIndex+1, // the internal API is 1-based
  146.                 locator.m_Chunk,
  147.                 skip, sdesc);
  148.         }
  149.     }
  150.     // update the stbl atoms and compute the mdat size
  151.     AP4_Size mdat_size = 0;
  152.     int current_track  = -1;
  153.     int current_chunk  = -1;
  154.     AP4_Offset current_chunk_offset = 0;
  155.     AP4_Size current_chunk_size = 0;
  156.     for (AP4_Ordinal i=0; i<locators.ItemCount(); i++) {
  157.         AP4_SampleLocator& locator = locators[i];
  158.         if ((int)locator.m_TrakIndex != current_track ||
  159.             (int)locator.m_Chunk     != current_chunk) {
  160.             // start a new chunk for this track
  161.             current_chunk_offset += current_chunk_size;
  162.             current_chunk_size = 0;
  163.             current_track = locator.m_TrakIndex;
  164.             current_chunk = locator.m_Chunk;
  165.             locator.m_SampleTable->SetChunkOffset(locator.m_Chunk, 
  166.                 current_chunk_offset);
  167.         } 
  168.         AP4_Size sample_size;
  169.         TrackHandler* handler = handlers[locator.m_TrakIndex];
  170.         if (handler) {
  171.             sample_size = handler->GetProcessedSampleSize(locator.m_Sample);
  172.             locator.m_SampleTable->SetSampleSize(locator.m_SampleIndex+1, sample_size);
  173.         } else {
  174.             sample_size = locator.m_Sample.GetSize();
  175.         }
  176.         current_chunk_size += sample_size;
  177.         mdat_size += sample_size;
  178.     }
  179.     // process the tracks (ex: sample descriptions processing)
  180.     for (AP4_Ordinal i=0; i<track_count; i++) {
  181.         TrackHandler* handler = handlers[i];
  182.         if (handler) handler->ProcessTrack();
  183.     }
  184.     // initialize the processor
  185.     Finalize(top_level);
  186.     // calculate the size of all atoms combined
  187.     AP4_Size atoms_size = 0;
  188.     top_level.GetChildren().Apply(AP4_AtomSizeAdder(atoms_size));
  189.     // adjust the chunk offsets
  190.     for (AP4_Ordinal i=0; i<track_count; i++) {
  191.         AP4_TrakAtom* trak;
  192.         trak_atoms.Get(i, trak);
  193.         trak->AdjustChunkOffsets(atoms_size+AP4_ATOM_HEADER_SIZE);
  194.     }
  195.     // write all atoms
  196.     top_level.GetChildren().Apply(AP4_AtomListWriter(output));
  197.     // write mdat header
  198.     output.WriteUI32(mdat_size+AP4_ATOM_HEADER_SIZE);
  199.     output.WriteUI32(AP4_ATOM_TYPE_MDAT);
  200. #if defined(AP4_DEBUG)
  201.     AP4_Offset before;
  202.     output.Tell(before);
  203. #endif
  204.     // write the samples
  205.     AP4_Sample sample;
  206.     AP4_DataBuffer data_in;
  207.     AP4_DataBuffer data_out;
  208.     for (unsigned int i=0; i<locators.ItemCount(); i++) {
  209.         AP4_SampleLocator& locator = locators[i];
  210.         locator.m_Sample.ReadData(data_in);
  211.         TrackHandler* handler = handlers[locator.m_TrakIndex];
  212.         if (handler) {
  213.             handler->ProcessSample(data_in, data_out);
  214.             output.Write(data_out.GetData(), data_out.GetDataSize());
  215.         } else {
  216.             output.Write(data_in.GetData(), data_in.GetDataSize());            
  217.         }
  218.     }
  219. #if defined(AP4_DEBUG)
  220.     AP4_Offset after;
  221.     output.Tell(after);
  222.     AP4_ASSERT(after-before == mdat_size);
  223. #endif
  224.     // cleanup
  225.     delete[] cursors;
  226.     for (unsigned int i=0; i<track_count; i++) {
  227.         delete handlers[i];
  228.     }
  229.     delete[] handlers;
  230.     return AP4_SUCCESS;
  231. }
  232. /*----------------------------------------------------------------------
  233. |       AP4_Processor:Initialize
  234. +---------------------------------------------------------------------*/
  235. AP4_Result 
  236. AP4_Processor::Initialize(AP4_AtomParent& top_level)
  237. {
  238.     // default implementation: do nothing
  239.     return AP4_SUCCESS;
  240. }
  241. /*----------------------------------------------------------------------
  242. |       AP4_Processor:Finalize
  243. +---------------------------------------------------------------------*/
  244. AP4_Result 
  245. AP4_Processor::Finalize(AP4_AtomParent& top_level)
  246. {
  247.     // default implementation: do nothing
  248.     return AP4_SUCCESS;
  249. }
  250. /*----------------------------------------------------------------------
  251. |       AP4_Processor:CreateTrackHandler
  252. +---------------------------------------------------------------------*/
  253. AP4_Processor::TrackHandler* 
  254. AP4_Processor::CreateTrackHandler(AP4_TrakAtom* /* trak */)
  255. {
  256.     // default implementation: no handler
  257.     return NULL;
  258. }
  259. /*----------------------------------------------------------------------
  260. |       AP4_Processor::TrackHandler::GetProcessedSampleSize
  261. +---------------------------------------------------------------------*/
  262. AP4_Size   
  263. AP4_Processor::TrackHandler::GetProcessedSampleSize(AP4_Sample& sample)
  264. {
  265.     // default implementation: do no change the sample size
  266.     return sample.GetSize();
  267. }