• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------
2  * Copyright (C) 1998-2009 PacketVideo
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13  * express or implied.
14  * See the License for the specific language governing permissions
15  * and limitations under the License.
16  * -------------------------------------------------------------------
17  */
18 /*
19     This PVA_FF_SampleSizeAtom Class contains the sample count and a table giving the
20     size of each sample.
21 */
22 
23 
24 #define IMPLEMENT_SampleToChunkAtom_H__
25 
26 #include "sampletochunkatom.h"
27 #include "atomutils.h"
28 #include "a_atomdefs.h"
29 
30 
31 const int32 PVA_FF_SampleToChunkAtom::DEFAULT_MAX_NUM_SAMPLES_PER_CHUNK = 20;
32 const int32 PVA_FF_SampleToChunkAtom::DEFAULT_MAX_CHUNK_DATA_SIZE = 10240; // 10KB
33 
34 typedef Oscl_Vector<uint32, OsclMemAllocator> uint32VecType;
35 
36 // Constructor
PVA_FF_SampleToChunkAtom(uint32 mediaType,uint32 fileAuthoringFlags)37 PVA_FF_SampleToChunkAtom::PVA_FF_SampleToChunkAtom(uint32 mediaType,
38         uint32 fileAuthoringFlags)
39         : PVA_FF_FullAtom(SAMPLE_TO_CHUNK_ATOM, (uint8)0, (uint32)0),
40         _mediaType(mediaType)
41 {
42     _oInterLeaveMode = false;
43     if (fileAuthoringFlags & PVMP4FF_SET_MEDIA_INTERLEAVE_MODE)
44     {
45         _oInterLeaveMode = true;
46     }
47 
48     _currIndex = 0;
49     _entryCount = 0;
50 
51     PV_MP4_FF_NEW(fp->auditCB, uint32VecType, (), _pfirstChunkVec);
52 
53     PV_MP4_FF_NEW(fp->auditCB, uint32VecType, (), _psamplesPerChunkVec);
54 
55     PV_MP4_FF_NEW(fp->auditCB, uint32VecType, (), _psampleDescriptionIndexVec);
56 
57 
58     _currentChunkNumber = 0;
59     _currentChunkDataSize = 0;
60     _currentChunkNumSamples = 0;
61     _maxNumSamplesPerChunk = DEFAULT_MAX_NUM_SAMPLES_PER_CHUNK;
62     _maxChunkDataSize = DEFAULT_MAX_CHUNK_DATA_SIZE;
63 
64     recomputeSize();
65 }
66 
~PVA_FF_SampleToChunkAtom()67 PVA_FF_SampleToChunkAtom::~PVA_FF_SampleToChunkAtom()
68 {
69     // Cleanup vectors
70     PV_MP4_FF_TEMPLATED_DELETE(NULL, uint32VecType, Oscl_Vector, _pfirstChunkVec);
71     PV_MP4_FF_TEMPLATED_DELETE(NULL, uint32VecType, Oscl_Vector, _psamplesPerChunkVec);
72     PV_MP4_FF_TEMPLATED_DELETE(NULL, uint32VecType, Oscl_Vector, _psampleDescriptionIndexVec);
73 }
74 bool
nextSample(int32 index,uint32 size,bool oChunkStart)75 PVA_FF_SampleToChunkAtom::nextSample(int32 index,
76                                      uint32 size,
77                                      bool oChunkStart)
78 {
79     // Check to see if this sample fp the start of a new chunk
80     bool newChunk;
81 
82     if (_oInterLeaveMode)
83     {
84         if (_pfirstChunkVec->size() == 0)
85         {
86             newChunk = true;
87         }
88         else
89         {
90             newChunk = oChunkStart;
91         }
92     }
93     else
94     {
95         newChunk = isNewChunk(size, index);
96     }
97 
98     if (newChunk)
99     {
100         if (_pfirstChunkVec->size() <= 1)
101         {
102             // Only zero or one run of chunks -
103             // add new entry in table
104             addChunkEntry(getNextChunkNumber(), (uint32)1, (uint32)index);
105             // first sample in this chunk
106             // Assuming ONLY 1 PVA_FF_SampleEntry FOR NOW!
107         }
108         else
109         {
110             // Check if samples per chunk for last entry is the same as the previous
111             // entry - if so, last entry can be merged with previous one - then add
112             // new entry (i.e. replace last entry with new entry)
113             if ((((*_psamplesPerChunkVec)[uint32(_pfirstChunkVec->size()-1)]) ==
114                     ((*_psamplesPerChunkVec)[uint32(_pfirstChunkVec->size()-2)])) &&
115                     (((*_psampleDescriptionIndexVec)[uint32(_pfirstChunkVec->size()-1)]) ==
116                      ((*_psampleDescriptionIndexVec)[uint32(_pfirstChunkVec->size()-2)])))
117 
118             {
119                 // SamplesPerChunk entries are the same - last chunk entry can be included
120                 // with the previous entry - Remove the last entry and add the entry for
121                 // the new chunk
122                 replaceLastChunkEntry(getNextChunkNumber(), (uint32)1, (uint32)index);
123             }
124             else
125             {
126                 // Samples per chunk values differ - just add new entry
127                 addChunkEntry(getNextChunkNumber(), (uint32)1, (uint32)index);
128             }
129         }
130     }
131     else
132     {
133         // Just another sample in this chunk - update entry
134         uint32 chunkNumber = _pfirstChunkVec->back();
135         uint32 samples = _psamplesPerChunkVec->back();
136         uint32 index = _psampleDescriptionIndexVec->back();
137 
138         samples += 1; // Increment the sample count for thic chunk
139 
140         // Update the entry for this chunk
141         replaceLastChunkEntry(chunkNumber, samples, index);
142     }
143 
144     return newChunk;
145 
146 }
147 
148 bool
isNewChunk(uint32 size,int32 index)149 PVA_FF_SampleToChunkAtom::isNewChunk(uint32 size, int32 index)
150 {
151     if (index != _currIndex)
152     {
153         _currIndex = index;
154         return true;
155     }
156 
157     // This method uses three heuristics to determine when a sample fp the start of
158     // a new chunk:
159     // 1. Every I-frame fp the start of a new chunk
160     // 2. A new chunk fp started when the current chunk size reaches a limit (in bytes)
161     // 3. A new chunk fp started when the current number of samples in a chunk reaches
162     //    a predefined limit (in number of samples)
163     // Note that number 1. fp for VIDEO samples ONLY!
164     // Also note that the first sample received fp also the start of a new chunk (degenerate case)
165 
166     // If this fp the first sample received - it fp the start of a new chunk
167     // This corresponds to the vectors of size zero
168     if (_pfirstChunkVec->size() == 0)
169     {
170         // First sample - new chunk
171         _currentChunkNumSamples = 1;
172         _currentChunkDataSize = size;
173         return true;
174     }
175 
176     // 3. Check for max num samples per chunk - if at max return true so this
177     // sample fp the start of a new chunk
178     if (_currentChunkNumSamples == _maxNumSamplesPerChunk)
179     {
180         // This sample starts a new chunk - thus 1 sample
181         // Update size of chunk to be size of this sample
182         _currentChunkNumSamples = 1;
183         _currentChunkDataSize = size;
184         return true;
185     }
186     else
187     {
188         // Not a new chunk so simply increment value
189         _currentChunkNumSamples += 1;
190     }
191 
192     // 2. Check for the actual size of each chunk - if at max return true so this
193     // sample fp the start of a new chunk
194     switch (_mediaType)
195     {
196         case MEDIA_TYPE_TEXT://added for timed text support
197         case MEDIA_TYPE_AUDIO:
198         case MEDIA_TYPE_VISUAL:
199         {
200             // Checking actual data size - if current chunk size plus this sample
201             // fp greater than the max allowed chunk size, this sample fp the start
202             // of a new chunk
203             if (_currentChunkDataSize + size > _maxChunkDataSize)
204             {
205                 // This sample starts a new chunk - thus 1 sample
206                 // Update size of chunk to be size of this sample
207                 _currentChunkNumSamples = 1;
208                 _currentChunkDataSize = size;
209                 return true;
210             }
211             else
212             {
213                 _currentChunkDataSize += size;
214             }
215         }
216         break;
217         case MEDIA_TYPE_UNKNOWN:
218         default:
219             break;
220     }
221 
222     // Default case - start a new chunk
223     return false;
224 }
225 
226 
227 // Adding to and getting first chunk, samples per chunk, and sample
228 // description index values
229 void
addChunkEntry(uint32 chunk,uint32 samples,uint32 index)230 PVA_FF_SampleToChunkAtom::addChunkEntry(uint32 chunk, uint32 samples, uint32 index)
231 {
232     _pfirstChunkVec->push_back(chunk);
233     _psamplesPerChunkVec->push_back(samples);
234     _psampleDescriptionIndexVec->push_back(index);
235     _entryCount += 1;
236 
237     recomputeSize();
238 }
239 
240 // Updates the last chunk entry by incrementing the samples
241 void
replaceLastChunkEntry(uint32 chunk,uint32 samples,uint32 index)242 PVA_FF_SampleToChunkAtom::replaceLastChunkEntry(uint32 chunk, uint32 samples, uint32 index)
243 {
244     _pfirstChunkVec->pop_back();
245     _psamplesPerChunkVec->pop_back();
246     _psampleDescriptionIndexVec->pop_back();
247 
248     _pfirstChunkVec->push_back(chunk);
249     _psamplesPerChunkVec->push_back(samples);
250     _psampleDescriptionIndexVec->push_back(index);
251 }
252 
253 
254 // Returns the samples description index for the samples in all the chunks in run[index]
255 int32
getSampleDescriptionIndexAt(uint32 index)256 PVA_FF_SampleToChunkAtom::getSampleDescriptionIndexAt(uint32 index)
257 {
258     if (index < _psampleDescriptionIndexVec->size())
259     {
260         return (*_psampleDescriptionIndexVec)[index];
261     }
262     else
263     {
264         return PV_ERROR;
265     }
266 }
267 
268 
269 // Rendering the PVA_FF_Atom in proper format (bitlengths, etc.) to an ostream
270 bool
renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP * fp)271 PVA_FF_SampleToChunkAtom::renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP *fp)
272 {
273     int32 rendered = 0;
274 
275     if (!renderAtomBaseMembers(fp))
276     {
277         return false;
278     }
279     rendered += getDefaultSize();
280 
281     if (!PVA_FF_AtomUtils::render32(fp, getEntryCount()))
282     {
283         return false;
284     }
285     rendered += 4;
286 
287     // Need to render in a 1-based index vector instead of a 0-based index array
288     int32 ARRAY_OFFSET_1_BASE = 1;
289     if ((_pfirstChunkVec->size() < _entryCount) ||
290             (_psamplesPerChunkVec->size() < _entryCount) ||
291             (_psampleDescriptionIndexVec->size() < _entryCount))
292     {
293         return false;
294     }
295     for (uint32 i = 0; i < _entryCount; i++)
296     {
297         if (!PVA_FF_AtomUtils::render32(fp, (*_pfirstChunkVec)[i] + ARRAY_OFFSET_1_BASE))
298         {
299             return false;
300         }
301         if (!PVA_FF_AtomUtils::render32(fp, (*_psamplesPerChunkVec)[i]))
302         {
303             return false;
304         }
305         if (!PVA_FF_AtomUtils::render32(fp, (*_psampleDescriptionIndexVec)[i]))
306         {
307             return false;
308         }
309     }
310     rendered += 12 * _entryCount;
311 
312     return true;
313 }
314 
315 void
recomputeSize()316 PVA_FF_SampleToChunkAtom::recomputeSize()
317 {
318     int32 size = getDefaultSize();
319     size += 4; // For entryCount
320 
321     size += 12 * _entryCount; // For each of the 3 4-byte entries
322 
323     _size = size;
324 
325     // Update size of parent atom
326     if (_pparent != NULL)
327     {
328         _pparent->recomputeSize();
329     }
330 }
331