| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 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> |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 27 | #include <media/stagefright/foundation/hexdump.h> |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 28 | |
| 29 | namespace android { |
| 30 | |
| 31 | Parser::DynamicTrackFragment::DynamicTrackFragment() |
| 32 | : mComplete(false), |
| 33 | mSampleIndex(0) { |
| 34 | } |
| 35 | |
| 36 | Parser::DynamicTrackFragment::~DynamicTrackFragment() { |
| 37 | } |
| 38 | |
| 39 | status_t Parser::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 Parser::DynamicTrackFragment::advance() { |
| 50 | ++mSampleIndex; |
| 51 | } |
| 52 | |
| 53 | void Parser::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 Parser::DynamicTrackFragment::signalCompletion() { |
| 69 | mComplete = true; |
| 70 | |
| 71 | return OK; |
| 72 | } |
| 73 | |
| 74 | bool Parser::DynamicTrackFragment::complete() const { |
| 75 | return mComplete; |
| 76 | } |
| 77 | |
| 78 | //////////////////////////////////////////////////////////////////////////////// |
| 79 | |
| 80 | Parser::StaticTrackFragment::StaticTrackFragment() |
| 81 | : mSampleIndex(0), |
| 82 | mSampleCount(0), |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 83 | mChunkIndex(0), |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 84 | mSampleToChunkIndex(-1), |
| 85 | mSampleToChunkRemaining(0), |
| 86 | mPrevChunkIndex(0xffffffff), |
| 87 | mNextSampleOffset(0) { |
| 88 | } |
| 89 | |
| 90 | Parser::StaticTrackFragment::~StaticTrackFragment() { |
| 91 | } |
| 92 | |
| 93 | status_t Parser::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 Parser::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 | |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 154 | if (mChunkIndex != mPrevChunkIndex) { |
| 155 | mPrevChunkIndex = mChunkIndex; |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 156 | |
| 157 | if (mChunkOffsets != NULL) { |
| 158 | uint32_t entryCount = U32_AT(mChunkOffsets->data() + 4); |
| 159 | |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 160 | if (mChunkIndex >= entryCount) { |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 161 | mSampleIndex = mSampleCount; |
| 162 | return; |
| 163 | } |
| 164 | |
| 165 | mNextSampleOffset = |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 166 | U32_AT(mChunkOffsets->data() + 8 + 4 * mChunkIndex); |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 167 | } else { |
| 168 | CHECK(mChunkOffsets64 != NULL); |
| 169 | |
| 170 | uint32_t entryCount = U32_AT(mChunkOffsets64->data() + 4); |
| 171 | |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 172 | if (mChunkIndex >= entryCount) { |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 173 | mSampleIndex = mSampleCount; |
| 174 | return; |
| 175 | } |
| 176 | |
| 177 | mNextSampleOffset = |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 178 | U64_AT(mChunkOffsets64->data() + 8 + 8 * mChunkIndex); |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 179 | } |
| 180 | } |
| 181 | |
| 182 | mSampleInfo.mOffset = mNextSampleOffset; |
| 183 | |
| 184 | mSampleInfo.mPresentationTime = 0; |
| 185 | mSampleInfo.mFlags = 0; |
| 186 | } |
| 187 | |
| 188 | void Parser::StaticTrackFragment::advance() { |
| 189 | mNextSampleOffset += mSampleInfo.mSize; |
| 190 | |
| 191 | ++mSampleIndex; |
| 192 | if (--mSampleToChunkRemaining == 0) { |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 193 | ++mChunkIndex; |
| 194 | |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 195 | uint32_t entryCount = U32_AT(mSampleToChunk->data() + 4); |
| 196 | |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 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 | } |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 210 | } |
| 211 | |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 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 | |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 226 | status_t Parser::StaticTrackFragment::signalCompletion() { |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 227 | mSampleToChunkIndex = 0; |
| 228 | |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 229 | mSampleToChunkRemaining = |
| 230 | (mSampleToChunk == NULL) |
| 231 | ? 0 |
| 232 | : U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4); |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 233 | |
| 234 | updateSampleInfo(); |
| 235 | |
| 236 | return OK; |
| 237 | } |
| 238 | |
| 239 | bool Parser::StaticTrackFragment::complete() const { |
| 240 | return true; |
| 241 | } |
| 242 | |
| 243 | status_t Parser::StaticTrackFragment::parseSampleSizes( |
| 244 | Parser *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 Parser::StaticTrackFragment::parseCompactSampleSizes( |
| 268 | Parser *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 Parser::StaticTrackFragment::parseSampleToChunk( |
| 297 | Parser *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 | |
| Marco Nelissen | b7e75cf | 2012-08-08 09:19:05 -0700 | [diff] [blame] | 308 | if (entryCount == 0) { |
| 309 | return OK; |
| 310 | } |
| 311 | |
| 312 | if (offset + 8 + entryCount * 12 != size) { |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 313 | return ERROR_MALFORMED; |
| 314 | } |
| 315 | |
| Andreas Huber | b978714 | 2012-08-09 09:15:48 -0700 | [diff] [blame] | 316 | parser->copyBuffer(&mSampleToChunk, offset, size); |
| Andreas Huber | 8406678 | 2011-08-16 09:34:26 -0700 | [diff] [blame] | 317 | |
| 318 | return OK; |
| 319 | } |
| 320 | |
| 321 | status_t Parser::StaticTrackFragment::parseChunkOffsets( |
| 322 | Parser *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 Parser::StaticTrackFragment::parseChunkOffsets64( |
| 343 | Parser *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 | |