Home | History | Annotate | Download | only in mp4
      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