1 /* 2 * Copyright (C) 2012 The Android Open Source Project 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 express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "TrackFragment" 19 #include <utils/Log.h> 20 21 #include "TrackFragment.h" 22 23 #include <media/stagefright/MediaErrors.h> 24 #include <media/stagefright/Utils.h> 25 #include <media/stagefright/foundation/ABuffer.h> 26 #include <media/stagefright/foundation/ADebug.h> 27 #include <media/stagefright/foundation/hexdump.h> 28 29 namespace android { 30 31 FragmentedMP4Parser::DynamicTrackFragment::DynamicTrackFragment() 32 : mComplete(false), 33 mSampleIndex(0) { 34 } 35 36 FragmentedMP4Parser::DynamicTrackFragment::~DynamicTrackFragment() { 37 } 38 39 status_t FragmentedMP4Parser::DynamicTrackFragment::getSample(SampleInfo *info) { 40 if (mSampleIndex >= mSamples.size()) { 41 return mComplete ? ERROR_END_OF_STREAM : -EWOULDBLOCK; 42 } 43 44 *info = mSamples.itemAt(mSampleIndex); 45 46 return OK; 47 } 48 49 void FragmentedMP4Parser::DynamicTrackFragment::advance() { 50 ++mSampleIndex; 51 } 52 53 void FragmentedMP4Parser::DynamicTrackFragment::addSample( 54 off64_t dataOffset, size_t sampleSize, 55 uint32_t presentationTime, 56 size_t sampleDescIndex, 57 uint32_t flags) { 58 mSamples.push(); 59 SampleInfo *sampleInfo = &mSamples.editItemAt(mSamples.size() - 1); 60 61 sampleInfo->mOffset = dataOffset; 62 sampleInfo->mSize = sampleSize; 63 sampleInfo->mPresentationTime = presentationTime; 64 sampleInfo->mSampleDescIndex = sampleDescIndex; 65 sampleInfo->mFlags = flags; 66 } 67 68 status_t FragmentedMP4Parser::DynamicTrackFragment::signalCompletion() { 69 mComplete = true; 70 71 return OK; 72 } 73 74 bool FragmentedMP4Parser::DynamicTrackFragment::complete() const { 75 return mComplete; 76 } 77 78 //////////////////////////////////////////////////////////////////////////////// 79 80 FragmentedMP4Parser::StaticTrackFragment::StaticTrackFragment() 81 : mSampleIndex(0), 82 mSampleCount(0), 83 mChunkIndex(0), 84 mSampleToChunkIndex(-1), 85 mSampleToChunkRemaining(0), 86 mPrevChunkIndex(0xffffffff), 87 mNextSampleOffset(0) { 88 } 89 90 FragmentedMP4Parser::StaticTrackFragment::~StaticTrackFragment() { 91 } 92 93 status_t FragmentedMP4Parser::StaticTrackFragment::getSample(SampleInfo *info) { 94 if (mSampleIndex >= mSampleCount) { 95 return ERROR_END_OF_STREAM; 96 } 97 98 *info = mSampleInfo; 99 100 ALOGV("returning sample %d at [0x%08llx, 0x%08llx)", 101 mSampleIndex, 102 info->mOffset, info->mOffset + info->mSize); 103 104 return OK; 105 } 106 107 void FragmentedMP4Parser::StaticTrackFragment::updateSampleInfo() { 108 if (mSampleIndex >= mSampleCount) { 109 return; 110 } 111 112 if (mSampleSizes != NULL) { 113 uint32_t defaultSampleSize = U32_AT(mSampleSizes->data() + 4); 114 if (defaultSampleSize > 0) { 115 mSampleInfo.mSize = defaultSampleSize; 116 } else { 117 mSampleInfo.mSize= U32_AT(mSampleSizes->data() + 12 + 4 * mSampleIndex); 118 } 119 } else { 120 CHECK(mCompactSampleSizes != NULL); 121 122 uint32_t fieldSize = U32_AT(mCompactSampleSizes->data() + 4); 123 124 switch (fieldSize) { 125 case 4: 126 { 127 unsigned byte = mCompactSampleSizes->data()[12 + mSampleIndex / 2]; 128 mSampleInfo.mSize = (mSampleIndex & 1) ? byte & 0x0f : byte >> 4; 129 break; 130 } 131 132 case 8: 133 { 134 mSampleInfo.mSize = mCompactSampleSizes->data()[12 + mSampleIndex]; 135 break; 136 } 137 138 default: 139 { 140 CHECK_EQ(fieldSize, 16); 141 mSampleInfo.mSize = 142 U16_AT(mCompactSampleSizes->data() + 12 + mSampleIndex * 2); 143 break; 144 } 145 } 146 } 147 148 CHECK_GT(mSampleToChunkRemaining, 0); 149 150 // The sample desc index is 1-based... XXX 151 mSampleInfo.mSampleDescIndex = 152 U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 8); 153 154 if (mChunkIndex != mPrevChunkIndex) { 155 mPrevChunkIndex = mChunkIndex; 156 157 if (mChunkOffsets != NULL) { 158 uint32_t entryCount = U32_AT(mChunkOffsets->data() + 4); 159 160 if (mChunkIndex >= entryCount) { 161 mSampleIndex = mSampleCount; 162 return; 163 } 164 165 mNextSampleOffset = 166 U32_AT(mChunkOffsets->data() + 8 + 4 * mChunkIndex); 167 } else { 168 CHECK(mChunkOffsets64 != NULL); 169 170 uint32_t entryCount = U32_AT(mChunkOffsets64->data() + 4); 171 172 if (mChunkIndex >= entryCount) { 173 mSampleIndex = mSampleCount; 174 return; 175 } 176 177 mNextSampleOffset = 178 U64_AT(mChunkOffsets64->data() + 8 + 8 * mChunkIndex); 179 } 180 } 181 182 mSampleInfo.mOffset = mNextSampleOffset; 183 184 mSampleInfo.mPresentationTime = 0; 185 mSampleInfo.mFlags = 0; 186 } 187 188 void FragmentedMP4Parser::StaticTrackFragment::advance() { 189 mNextSampleOffset += mSampleInfo.mSize; 190 191 ++mSampleIndex; 192 if (--mSampleToChunkRemaining == 0) { 193 ++mChunkIndex; 194 195 uint32_t entryCount = U32_AT(mSampleToChunk->data() + 4); 196 197 // If this is the last entry in the sample to chunk table, we will 198 // stay on this entry. 199 if ((uint32_t)(mSampleToChunkIndex + 1) < entryCount) { 200 uint32_t nextChunkIndex = 201 U32_AT(mSampleToChunk->data() + 8 + 12 * (mSampleToChunkIndex + 1)); 202 203 CHECK_GE(nextChunkIndex, 1u); 204 --nextChunkIndex; 205 206 if (mChunkIndex >= nextChunkIndex) { 207 CHECK_EQ(mChunkIndex, nextChunkIndex); 208 ++mSampleToChunkIndex; 209 } 210 } 211 212 mSampleToChunkRemaining = 213 U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4); 214 } 215 216 updateSampleInfo(); 217 } 218 219 static void setU32At(uint8_t *ptr, uint32_t x) { 220 ptr[0] = x >> 24; 221 ptr[1] = (x >> 16) & 0xff; 222 ptr[2] = (x >> 8) & 0xff; 223 ptr[3] = x & 0xff; 224 } 225 226 status_t FragmentedMP4Parser::StaticTrackFragment::signalCompletion() { 227 mSampleToChunkIndex = 0; 228 229 mSampleToChunkRemaining = 230 (mSampleToChunk == NULL) 231 ? 0 232 : U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4); 233 234 updateSampleInfo(); 235 236 return OK; 237 } 238 239 bool FragmentedMP4Parser::StaticTrackFragment::complete() const { 240 return true; 241 } 242 243 status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes( 244 FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { 245 if (offset + 12 > size) { 246 return ERROR_MALFORMED; 247 } 248 249 if (parser->readU32(offset) != 0) { 250 return ERROR_MALFORMED; 251 } 252 253 uint32_t sampleSize = parser->readU32(offset + 4); 254 uint32_t sampleCount = parser->readU32(offset + 8); 255 256 if (sampleSize == 0 && offset + 12 + sampleCount * 4 != size) { 257 return ERROR_MALFORMED; 258 } 259 260 parser->copyBuffer(&mSampleSizes, offset, size); 261 262 mSampleCount = sampleCount; 263 264 return OK; 265 } 266 267 status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes( 268 FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { 269 if (offset + 12 > size) { 270 return ERROR_MALFORMED; 271 } 272 273 if (parser->readU32(offset) != 0) { 274 return ERROR_MALFORMED; 275 } 276 277 uint32_t fieldSize = parser->readU32(offset + 4); 278 279 if (fieldSize != 4 && fieldSize != 8 && fieldSize != 16) { 280 return ERROR_MALFORMED; 281 } 282 283 uint32_t sampleCount = parser->readU32(offset + 8); 284 285 if (offset + 12 + (sampleCount * fieldSize + 4) / 8 != size) { 286 return ERROR_MALFORMED; 287 } 288 289 parser->copyBuffer(&mCompactSampleSizes, offset, size); 290 291 mSampleCount = sampleCount; 292 293 return OK; 294 } 295 296 status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk( 297 FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { 298 if (offset + 8 > size) { 299 return ERROR_MALFORMED; 300 } 301 302 if (parser->readU32(offset) != 0) { 303 return ERROR_MALFORMED; 304 } 305 306 uint32_t entryCount = parser->readU32(offset + 4); 307 308 if (entryCount == 0) { 309 return OK; 310 } 311 312 if (offset + 8 + entryCount * 12 != size) { 313 return ERROR_MALFORMED; 314 } 315 316 parser->copyBuffer(&mSampleToChunk, offset, size); 317 318 return OK; 319 } 320 321 status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets( 322 FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { 323 if (offset + 8 > size) { 324 return ERROR_MALFORMED; 325 } 326 327 if (parser->readU32(offset) != 0) { 328 return ERROR_MALFORMED; 329 } 330 331 uint32_t entryCount = parser->readU32(offset + 4); 332 333 if (offset + 8 + entryCount * 4 != size) { 334 return ERROR_MALFORMED; 335 } 336 337 parser->copyBuffer(&mChunkOffsets, offset, size); 338 339 return OK; 340 } 341 342 status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets64( 343 FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) { 344 if (offset + 8 > size) { 345 return ERROR_MALFORMED; 346 } 347 348 if (parser->readU32(offset) != 0) { 349 return ERROR_MALFORMED; 350 } 351 352 uint32_t entryCount = parser->readU32(offset + 4); 353 354 if (offset + 8 + entryCount * 8 != size) { 355 return ERROR_MALFORMED; 356 } 357 358 parser->copyBuffer(&mChunkOffsets64, offset, size); 359 360 return OK; 361 } 362 363 } // namespace android 364 365