LCOV - code coverage report
Current view: top level - media/libstagefright/frameworks/av/media/libstagefright - SampleTable.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 556 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2009 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             : #undef LOG_TAG
      18             : #define LOG_TAG "SampleTable"
      19             : //#define LOG_NDEBUG 0
      20             : #include <utils/Log.h>
      21             : 
      22             : #include "include/SampleTable.h"
      23             : #include "include/SampleIterator.h"
      24             : 
      25             : #include <arpa/inet.h>
      26             : 
      27             : #include <media/stagefright/foundation/ADebug.h>
      28             : #include <media/stagefright/DataSource.h>
      29             : #include <media/stagefright/Utils.h>
      30             : 
      31             : #include "mozilla/SizePrintfMacros.h"
      32             : 
      33             : #include <cinttypes>
      34             : #include <stdint.h>
      35             : 
      36             : namespace stagefright {
      37             : 
      38             : // static
      39             : const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
      40             : // static
      41             : const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
      42             : // static
      43             : const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
      44             : // static
      45             : const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
      46             : 
      47             : const uint32_t kAuxTypeCenc = FOURCC('c', 'e', 'n', 'c');
      48             : 
      49             : static const uint32_t kMAX_ALLOCATION =
      50             :     (SIZE_MAX < INT32_MAX ? SIZE_MAX : INT32_MAX) - 128;
      51             : 
      52             : ////////////////////////////////////////////////////////////////////////////////
      53             : 
      54           0 : struct SampleTable::CompositionDeltaLookup {
      55             :     CompositionDeltaLookup();
      56             : 
      57             :     void setEntries(
      58             :             const uint32_t *deltaEntries, size_t numDeltaEntries);
      59             : 
      60             :     uint32_t getCompositionTimeOffset(uint32_t sampleIndex);
      61             : 
      62             : private:
      63             :     Mutex mLock;
      64             : 
      65             :     const uint32_t *mDeltaEntries;
      66             :     size_t mNumDeltaEntries;
      67             : 
      68             :     size_t mCurrentDeltaEntry;
      69             :     size_t mCurrentEntrySampleIndex;
      70             : 
      71             :     DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup);
      72             : };
      73             : 
      74           0 : SampleTable::CompositionDeltaLookup::CompositionDeltaLookup()
      75             :     : mDeltaEntries(NULL),
      76             :       mNumDeltaEntries(0),
      77             :       mCurrentDeltaEntry(0),
      78           0 :       mCurrentEntrySampleIndex(0) {
      79           0 : }
      80             : 
      81           0 : void SampleTable::CompositionDeltaLookup::setEntries(
      82             :         const uint32_t *deltaEntries, size_t numDeltaEntries) {
      83           0 :     Mutex::Autolock autolock(mLock);
      84             : 
      85           0 :     mDeltaEntries = deltaEntries;
      86           0 :     mNumDeltaEntries = numDeltaEntries;
      87           0 :     mCurrentDeltaEntry = 0;
      88           0 :     mCurrentEntrySampleIndex = 0;
      89           0 : }
      90             : 
      91           0 : uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset(
      92             :         uint32_t sampleIndex) {
      93           0 :     Mutex::Autolock autolock(mLock);
      94             : 
      95           0 :     if (mDeltaEntries == NULL) {
      96           0 :         return 0;
      97             :     }
      98             : 
      99           0 :     if (sampleIndex < mCurrentEntrySampleIndex) {
     100           0 :         mCurrentDeltaEntry = 0;
     101           0 :         mCurrentEntrySampleIndex = 0;
     102             :     }
     103             : 
     104           0 :     while (mCurrentDeltaEntry < mNumDeltaEntries) {
     105           0 :         uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry];
     106           0 :         if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) {
     107           0 :             return mDeltaEntries[2 * mCurrentDeltaEntry + 1];
     108             :         }
     109             : 
     110           0 :         mCurrentEntrySampleIndex += sampleCount;
     111           0 :         ++mCurrentDeltaEntry;
     112             :     }
     113             : 
     114           0 :     return 0;
     115             : }
     116             : 
     117             : ////////////////////////////////////////////////////////////////////////////////
     118             : 
     119           0 : SampleTable::SampleTable(const sp<DataSource> &source)
     120             :     : mDataSource(source),
     121             :       mChunkOffsetOffset(-1),
     122             :       mChunkOffsetType(0),
     123             :       mNumChunkOffsets(0),
     124             :       mSampleToChunkOffset(-1),
     125             :       mNumSampleToChunkOffsets(0),
     126             :       mSampleSizeOffset(-1),
     127             :       mSampleSizeFieldSize(0),
     128             :       mDefaultSampleSize(0),
     129             :       mNumSampleSizes(0),
     130             :       mTimeToSampleCount(0),
     131             :       mTimeToSample(NULL),
     132             :       mSampleTimeEntries(NULL),
     133             :       mCompositionTimeDeltaEntries(NULL),
     134             :       mNumCompositionTimeDeltaEntries(0),
     135           0 :       mCompositionDeltaLookup(new CompositionDeltaLookup),
     136             :       mSyncSampleOffset(-1),
     137             :       mNumSyncSamples(0),
     138             :       mSyncSamples(NULL),
     139             :       mLastSyncSampleIndex(0),
     140             :       mSampleToChunkEntries(NULL),
     141             :       mCencInfo(NULL),
     142             :       mCencInfoCount(0),
     143           0 :       mCencDefaultSize(0)
     144             : {
     145           0 :     mSampleIterator = new SampleIterator(this);
     146           0 : }
     147             : 
     148           0 : SampleTable::~SampleTable() {
     149           0 :     delete[] mSampleToChunkEntries;
     150           0 :     mSampleToChunkEntries = NULL;
     151             : 
     152           0 :     delete[] mSyncSamples;
     153           0 :     mSyncSamples = NULL;
     154             : 
     155           0 :     delete mCompositionDeltaLookup;
     156           0 :     mCompositionDeltaLookup = NULL;
     157             : 
     158           0 :     delete[] mCompositionTimeDeltaEntries;
     159           0 :     mCompositionTimeDeltaEntries = NULL;
     160             : 
     161           0 :     delete[] mSampleTimeEntries;
     162           0 :     mSampleTimeEntries = NULL;
     163             : 
     164           0 :     delete[] mTimeToSample;
     165           0 :     mTimeToSample = NULL;
     166             : 
     167           0 :     if (mCencInfo) {
     168           0 :         for (uint32_t i = 0; i < mCencInfoCount; i++) {
     169           0 :             if (mCencInfo[i].mSubsamples) {
     170           0 :                 delete[] mCencInfo[i].mSubsamples;
     171             :             }
     172             :         }
     173           0 :         delete[] mCencInfo;
     174             :     }
     175             : 
     176           0 :     delete mSampleIterator;
     177           0 :     mSampleIterator = NULL;
     178           0 : }
     179             : 
     180           0 : bool SampleTable::isValid() const {
     181           0 :     return mChunkOffsetOffset >= 0
     182           0 :         && mSampleToChunkOffset >= 0
     183           0 :         && mSampleSizeOffset >= 0
     184           0 :         && mTimeToSample != NULL;
     185             : }
     186             : 
     187           0 : status_t SampleTable::setChunkOffsetParams(
     188             :         uint32_t type, off64_t data_offset, size_t data_size) {
     189           0 :     if (mChunkOffsetOffset >= 0) {
     190           0 :         return ERROR_MALFORMED;
     191             :     }
     192             : 
     193           0 :     CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
     194             : 
     195           0 :     mChunkOffsetOffset = data_offset;
     196           0 :     mChunkOffsetType = type;
     197             : 
     198           0 :     if (data_size < 8) {
     199           0 :         return ERROR_MALFORMED;
     200             :     }
     201             : 
     202             :     uint8_t header[8];
     203           0 :     if (mDataSource->readAt(
     204           0 :                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
     205           0 :         return ERROR_IO;
     206             :     }
     207             : 
     208           0 :     if (U32_AT(header) != 0) {
     209             :         // Expected version = 0, flags = 0.
     210           0 :         return ERROR_MALFORMED;
     211             :     }
     212             : 
     213           0 :     mNumChunkOffsets = U32_AT(&header[4]);
     214             : 
     215           0 :     if (mChunkOffsetType == kChunkOffsetType32) {
     216           0 :         if (data_size < 8 + (uint64_t)mNumChunkOffsets * 4) {
     217           0 :             return ERROR_MALFORMED;
     218             :         }
     219             :     } else {
     220           0 :         if (data_size < 8 + (uint64_t)mNumChunkOffsets * 8) {
     221           0 :             return ERROR_MALFORMED;
     222             :         }
     223             :     }
     224             : 
     225           0 :     return OK;
     226             : }
     227             : 
     228           0 : status_t SampleTable::setSampleToChunkParams(
     229             :         off64_t data_offset, size_t data_size) {
     230           0 :     if (mSampleToChunkOffset >= 0) {
     231           0 :         return ERROR_MALFORMED;
     232             :     }
     233             : 
     234           0 :     mSampleToChunkOffset = data_offset;
     235             : 
     236           0 :     if (data_size < 8) {
     237           0 :         return ERROR_MALFORMED;
     238             :     }
     239             : 
     240             :     uint8_t header[8];
     241           0 :     if (mDataSource->readAt(
     242           0 :                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
     243           0 :         return ERROR_IO;
     244             :     }
     245             : 
     246           0 :     if (U32_AT(header) != 0) {
     247             :         // Expected version = 0, flags = 0.
     248           0 :         return ERROR_MALFORMED;
     249             :     }
     250             : 
     251           0 :     mNumSampleToChunkOffsets = U32_AT(&header[4]);
     252             : 
     253           0 :     if (data_size < 8 + (uint64_t)mNumSampleToChunkOffsets * 12) {
     254           0 :         return ERROR_MALFORMED;
     255             :     }
     256             : 
     257           0 :     mSampleToChunkEntries =
     258           0 :         new (mozilla::fallible) SampleToChunkEntry[mNumSampleToChunkOffsets];
     259           0 :     if (!mSampleToChunkEntries) {
     260           0 :       return ERROR_BUFFER_TOO_SMALL;
     261             :     }
     262             : 
     263           0 :     for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
     264             :         uint8_t buffer[12];
     265           0 :         if (mDataSource->readAt(
     266           0 :                     mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
     267             :                 != (ssize_t)sizeof(buffer)) {
     268           0 :             return ERROR_IO;
     269             :         }
     270             : 
     271           0 :         if (!U32_AT(buffer)) {
     272           0 :           ALOGE("error reading sample to chunk table");
     273           0 :           return ERROR_MALFORMED;  // chunk index is 1 based in the spec.
     274             :         }
     275             : 
     276             :         // We want the chunk index to be 0-based.
     277           0 :         mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
     278           0 :         mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
     279           0 :         mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
     280             :     }
     281             : 
     282           0 :     return OK;
     283             : }
     284             : 
     285           0 : status_t SampleTable::setSampleSizeParams(
     286             :         uint32_t type, off64_t data_offset, size_t data_size) {
     287           0 :     if (mSampleSizeOffset >= 0) {
     288           0 :         return ERROR_MALFORMED;
     289             :     }
     290             : 
     291           0 :     CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
     292             : 
     293           0 :     mSampleSizeOffset = data_offset;
     294             : 
     295           0 :     if (data_size < 12) {
     296           0 :         return ERROR_MALFORMED;
     297             :     }
     298             : 
     299             :     uint8_t header[12];
     300           0 :     if (mDataSource->readAt(
     301           0 :                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
     302           0 :         return ERROR_IO;
     303             :     }
     304             : 
     305           0 :     if (U32_AT(header) != 0) {
     306             :         // Expected version = 0, flags = 0.
     307           0 :         return ERROR_MALFORMED;
     308             :     }
     309             : 
     310           0 :     mDefaultSampleSize = U32_AT(&header[4]);
     311           0 :     mNumSampleSizes = U32_AT(&header[8]);
     312             : 
     313           0 :     if (type == kSampleSizeType32) {
     314           0 :         mSampleSizeFieldSize = 32;
     315             : 
     316           0 :         if (mDefaultSampleSize != 0) {
     317           0 :             return OK;
     318             :         }
     319             : 
     320           0 :         if (data_size < 12 + (uint64_t)mNumSampleSizes * 4) {
     321           0 :             return ERROR_MALFORMED;
     322             :         }
     323             :     } else {
     324           0 :         if ((mDefaultSampleSize & 0xffffff00) != 0) {
     325             :             // The high 24 bits are reserved and must be 0.
     326           0 :             return ERROR_MALFORMED;
     327             :         }
     328             : 
     329           0 :         mSampleSizeFieldSize = mDefaultSampleSize & 0xff;
     330           0 :         mDefaultSampleSize = 0;
     331             : 
     332           0 :         if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
     333           0 :             && mSampleSizeFieldSize != 16) {
     334           0 :             return ERROR_MALFORMED;
     335             :         }
     336             : 
     337           0 :         if (data_size < 12 + ((uint64_t)mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
     338           0 :             return ERROR_MALFORMED;
     339             :         }
     340             :     }
     341             : 
     342           0 :     return OK;
     343             : }
     344             : 
     345           0 : status_t SampleTable::setTimeToSampleParams(
     346             :         off64_t data_offset, size_t data_size) {
     347           0 :     if (mTimeToSample != NULL || data_size < 8) {
     348           0 :         return ERROR_MALFORMED;
     349             :     }
     350             : 
     351             :     uint8_t header[8];
     352           0 :     if (mDataSource->readAt(
     353           0 :                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
     354           0 :         return ERROR_IO;
     355             :     }
     356             : 
     357           0 :     if (U32_AT(header) != 0) {
     358             :         // Expected version = 0, flags = 0.
     359           0 :         return ERROR_MALFORMED;
     360             :     }
     361             : 
     362           0 :     mTimeToSampleCount = U32_AT(&header[4]);
     363           0 :     if (mTimeToSampleCount > kMAX_ALLOCATION / 2 / sizeof(uint32_t)) {
     364             :         // Avoid later overflow.
     365           0 :         return ERROR_MALFORMED;
     366             :     }
     367             : 
     368           0 :     size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
     369             : 
     370           0 :     mTimeToSample = new (mozilla::fallible) uint32_t[mTimeToSampleCount * 2];
     371           0 :     if (!mTimeToSample) {
     372           0 :       return ERROR_BUFFER_TOO_SMALL;
     373             :     }
     374             : 
     375           0 :     if (mDataSource->readAt(
     376           0 :                 data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
     377           0 :         return ERROR_IO;
     378             :     }
     379             : 
     380           0 :     for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
     381           0 :         mTimeToSample[i] = ntohl(mTimeToSample[i]);
     382             :     }
     383             : 
     384           0 :     return OK;
     385             : }
     386             : 
     387           0 : status_t SampleTable::setCompositionTimeToSampleParams(
     388             :         off64_t data_offset, size_t data_size) {
     389             :     ALOGV("There are reordered frames present.");
     390             : 
     391           0 :     if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
     392           0 :         return ERROR_MALFORMED;
     393             :     }
     394             : 
     395             :     uint8_t header[8];
     396           0 :     if (mDataSource->readAt(
     397           0 :                 data_offset, header, sizeof(header))
     398             :             < (ssize_t)sizeof(header)) {
     399           0 :         return ERROR_IO;
     400             :     }
     401             : 
     402           0 :     uint32_t numEntries = U32_AT(&header[4]);
     403             : 
     404           0 :     if (U32_AT(header) != 0 && numEntries) {
     405             :         // Expected version = 0, flags = 0.
     406           0 :         return ERROR_MALFORMED;
     407             :     }
     408             : 
     409           0 :     if (data_size < ((uint64_t)numEntries + 1) * 8) {
     410           0 :         return ERROR_MALFORMED;
     411             :     }
     412             : 
     413           0 :     mNumCompositionTimeDeltaEntries = numEntries;
     414           0 :     mCompositionTimeDeltaEntries = new (mozilla::fallible) uint32_t[2 * numEntries];
     415           0 :     if (!mCompositionTimeDeltaEntries) {
     416           0 :       return ERROR_BUFFER_TOO_SMALL;
     417             :     }
     418             : 
     419           0 :     if (mDataSource->readAt(
     420           0 :                 data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
     421           0 :             < (ssize_t)numEntries * 8) {
     422           0 :         delete[] mCompositionTimeDeltaEntries;
     423           0 :         mCompositionTimeDeltaEntries = NULL;
     424             : 
     425           0 :         return ERROR_IO;
     426             :     }
     427             : 
     428           0 :     for (size_t i = 0; i < 2 * numEntries; ++i) {
     429           0 :         mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
     430             :     }
     431             : 
     432           0 :     mCompositionDeltaLookup->setEntries(
     433           0 :             mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
     434             : 
     435           0 :     return OK;
     436             : }
     437             : 
     438           0 : status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
     439           0 :     if (mSyncSampleOffset >= 0 || data_size < 8) {
     440           0 :         return ERROR_MALFORMED;
     441             :     }
     442             : 
     443           0 :     mSyncSampleOffset = data_offset;
     444             : 
     445             :     uint8_t header[8];
     446           0 :     if (mDataSource->readAt(
     447           0 :                 data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
     448           0 :         return ERROR_IO;
     449             :     }
     450             : 
     451           0 :     if (U32_AT(header) != 0) {
     452             :         // Expected version = 0, flags = 0.
     453           0 :         return ERROR_MALFORMED;
     454             :     }
     455             : 
     456           0 :     mNumSyncSamples = U32_AT(&header[4]);
     457           0 :     if (mNumSyncSamples > kMAX_ALLOCATION / sizeof(uint32_t)) {
     458             :         // Avoid later overflow.
     459           0 :         return ERROR_MALFORMED;
     460             :     }
     461             : 
     462           0 :     if (mNumSyncSamples < 2) {
     463             :         ALOGV("Table of sync samples is empty or has only a single entry!");
     464             :     }
     465             : 
     466           0 :     mSyncSamples = new (mozilla::fallible) uint32_t[mNumSyncSamples];
     467           0 :     if (!mSyncSamples) {
     468           0 :       return ERROR_BUFFER_TOO_SMALL;
     469             :     }
     470           0 :     size_t size = mNumSyncSamples * sizeof(uint32_t);
     471           0 :     if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
     472           0 :             != (ssize_t)size) {
     473           0 :         return ERROR_IO;
     474             :     }
     475             : 
     476           0 :     for (size_t i = 0; i < mNumSyncSamples; ++i) {
     477           0 :         mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
     478             :     }
     479             : 
     480           0 :     return OK;
     481             : }
     482             : 
     483             : static status_t
     484           0 : validateCencBoxHeader(
     485             :         sp<DataSource>& data_source, off64_t& data_offset,
     486             :         uint8_t* out_version, uint32_t* out_aux_type) {
     487           0 :     *out_aux_type = 0;
     488             : 
     489           0 :     if (data_source->readAt(data_offset++, out_version, 1) < 1) {
     490           0 :         ALOGE("error reading sample aux info header");
     491           0 :         return ERROR_IO;
     492             :     }
     493             : 
     494             :     uint32_t flags;
     495           0 :     if (!data_source->getUInt24(data_offset, &flags)) {
     496           0 :         ALOGE("error reading sample aux info flags");
     497           0 :         return ERROR_IO;
     498             :     }
     499           0 :     data_offset += 3;
     500             : 
     501           0 :     if (flags & 1) {
     502             :         uint32_t aux_type;
     503             :         uint32_t aux_param;
     504           0 :         if (!data_source->getUInt32(data_offset, &aux_type) ||
     505           0 :             !data_source->getUInt32(data_offset + 4, &aux_param)) {
     506           0 :             ALOGE("error reading aux info type");
     507           0 :             return ERROR_IO;
     508             :         }
     509           0 :         data_offset += 8;
     510           0 :         *out_aux_type = aux_type;
     511             :     }
     512             : 
     513           0 :     return OK;
     514             : }
     515             : 
     516             : status_t
     517           0 : SampleTable::setSampleAuxiliaryInformationSizeParams(
     518             :         off64_t data_offset, size_t data_size, uint32_t drm_scheme) {
     519           0 :     off64_t data_end = data_offset + data_size;
     520             : 
     521             :     uint8_t version;
     522             :     uint32_t aux_type;
     523           0 :     status_t err = validateCencBoxHeader(
     524           0 :                 mDataSource, data_offset, &version, &aux_type);
     525           0 :     if (err != OK) {
     526           0 :         return err;
     527             :     }
     528             : 
     529           0 :     if (aux_type && aux_type != kAuxTypeCenc && drm_scheme != kAuxTypeCenc) {
     530             :         // Quietly skip aux types we don't care about.
     531           0 :         return OK;
     532             :     }
     533             : 
     534           0 :     if (!mCencSizes.IsEmpty() || mCencDefaultSize) {
     535           0 :         ALOGE("duplicate cenc saiz box");
     536           0 :         return ERROR_MALFORMED;
     537             :     }
     538             : 
     539           0 :     if (version) {
     540             :         ALOGV("unsupported cenc saiz version");
     541           0 :         return ERROR_UNSUPPORTED;
     542             :     }
     543             : 
     544           0 :     if (mDataSource->readAt(
     545           0 :                 data_offset++, &mCencDefaultSize, sizeof(mCencDefaultSize))
     546             :                 < sizeof(mCencDefaultSize)) {
     547           0 :         return ERROR_IO;
     548             :     }
     549             : 
     550           0 :     if (!mDataSource->getUInt32(data_offset, &mCencInfoCount)) {
     551           0 :         return ERROR_IO;
     552             :     }
     553           0 :     data_offset += 4;
     554             : 
     555           0 :     if (!mCencDefaultSize) {
     556           0 :         if (!mCencSizes.InsertElementsAt(0, mCencInfoCount, mozilla::fallible)) {
     557           0 :           return ERROR_IO;
     558             :         }
     559           0 :         if (mDataSource->readAt(
     560           0 :                     data_offset, mCencSizes.Elements(), mCencInfoCount)
     561           0 :                     < mCencInfoCount) {
     562           0 :             return ERROR_IO;
     563             :         }
     564           0 :         data_offset += mCencInfoCount;
     565             :     }
     566             : 
     567           0 :     if (data_offset != data_end) {
     568           0 :         ALOGW("wrong saiz data size, expected %" PRIuSIZE ", actual %" PRIu64,
     569           0 :               data_size, uint64_t(data_offset - (data_end - data_size)));
     570             :         // Continue, assume extra data is not important.
     571             :         // Parser will skip past the box end.
     572             :     }
     573             : 
     574           0 :     return parseSampleCencInfo();
     575             : }
     576             : 
     577             : status_t
     578           0 : SampleTable::setSampleAuxiliaryInformationOffsetParams(
     579             :         off64_t data_offset, size_t data_size, uint32_t drm_scheme) {
     580           0 :     off64_t data_end = data_offset + data_size;
     581             : 
     582             :     uint8_t version;
     583             :     uint32_t aux_type;
     584           0 :     status_t err = validateCencBoxHeader(mDataSource, data_offset,
     585           0 :                                          &version, &aux_type);
     586           0 :     if (err != OK) {
     587           0 :         return err;
     588             :     }
     589             : 
     590           0 :     if (aux_type && aux_type != kAuxTypeCenc && drm_scheme != kAuxTypeCenc) {
     591             :         // Quietly skip aux types we don't care about.
     592           0 :         return OK;
     593             :     }
     594             : 
     595           0 :     if (!mCencOffsets.IsEmpty()) {
     596           0 :         ALOGE("duplicate cenc saio box");
     597           0 :         return ERROR_MALFORMED;
     598             :     }
     599             : 
     600             :     uint32_t cencOffsetCount;
     601           0 :     if (!mDataSource->getUInt32(data_offset, &cencOffsetCount)) {
     602           0 :         ALOGE("error reading cenc aux info offset count");
     603           0 :         return ERROR_IO;
     604             :     }
     605           0 :     data_offset += 4;
     606             : 
     607           0 :     if (cencOffsetCount >= kMAX_ALLOCATION) {
     608           0 :         return ERROR_MALFORMED;
     609             :     }
     610           0 :     if (!version) {
     611           0 :         if (!mCencOffsets.SetCapacity(cencOffsetCount, mozilla::fallible)) {
     612           0 :             return ERROR_MALFORMED;
     613             :         }
     614           0 :         for (uint32_t i = 0; i < cencOffsetCount; i++) {
     615             :             uint32_t tmp;
     616           0 :             if (!mDataSource->getUInt32(data_offset, &tmp)) {
     617           0 :                 ALOGE("error reading cenc aux info offsets");
     618           0 :                 return ERROR_IO;
     619             :             }
     620             :             // FIXME: Make this infallible after bug 968520 is done.
     621           0 :             MOZ_ALWAYS_TRUE(mCencOffsets.AppendElement(tmp, mozilla::fallible));
     622           0 :             data_offset += 4;
     623             :         }
     624             :     } else {
     625           0 :         if (!mCencOffsets.SetLength(cencOffsetCount, mozilla::fallible)) {
     626           0 :           return ERROR_MALFORMED;
     627             :         }
     628           0 :         for (uint32_t i = 0; i < cencOffsetCount; i++) {
     629           0 :             if (!mDataSource->getUInt64(data_offset, &mCencOffsets[i])) {
     630           0 :                 ALOGE("error reading cenc aux info offsets");
     631           0 :                 return ERROR_IO;
     632             :             }
     633           0 :             data_offset += 8;
     634             :         }
     635             :     }
     636             : 
     637           0 :     if (data_offset != data_end) {
     638           0 :         ALOGW("wrong saio data size, expected %" PRIuSIZE ", actual %" PRIu64,
     639           0 :               data_size, uint64_t(data_offset - (data_end - data_size)));
     640             :         // Continue, assume extra data is not important.
     641             :         // Parser will skip past the box end.
     642             :     }
     643             : 
     644           0 :     return parseSampleCencInfo();
     645             : }
     646             : 
     647             : status_t
     648           0 : SampleTable::parseSampleCencInfo() {
     649           0 :     if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.IsEmpty()) {
     650             :         // We don't have all the cenc information we need yet. Quietly fail and
     651             :         // hope we get the data we need later in the track header.
     652             :         ALOGV("Got half of cenc saio/saiz pair. Deferring parse until we get the other half.");
     653           0 :         return OK;
     654             :     }
     655             : 
     656           0 :     if ((mCencOffsets.Length() > 1 && mCencOffsets.Length() < mCencInfoCount) ||
     657           0 :         (!mCencDefaultSize && mCencSizes.Length() < mCencInfoCount)) {
     658           0 :         return ERROR_MALFORMED;
     659             :     }
     660             : 
     661           0 :     if (mCencInfoCount > kMAX_ALLOCATION / sizeof(SampleCencInfo)) {
     662             :         // Avoid future OOM.
     663           0 :         return ERROR_MALFORMED;
     664             :     }
     665             : 
     666           0 :     mCencInfo = new (mozilla::fallible) SampleCencInfo[mCencInfoCount];
     667           0 :     if (!mCencInfo) {
     668           0 :       return ERROR_BUFFER_TOO_SMALL;
     669             :     }
     670           0 :     for (uint32_t i = 0; i < mCencInfoCount; i++) {
     671           0 :         mCencInfo[i].mSubsamples = NULL;
     672             :     }
     673             : 
     674           0 :     uint64_t nextOffset = mCencOffsets[0];
     675           0 :     for (uint32_t i = 0; i < mCencInfoCount; i++) {
     676           0 :         uint8_t size = mCencDefaultSize ? mCencDefaultSize : mCencSizes[i];
     677           0 :         uint64_t offset = mCencOffsets.Length() == 1 ? nextOffset : mCencOffsets[i];
     678           0 :         nextOffset = offset + size;
     679             : 
     680           0 :         auto& info = mCencInfo[i];
     681             : 
     682           0 :         if (size < IV_BYTES) {
     683           0 :             ALOGE("cenc aux info too small");
     684           0 :             return ERROR_MALFORMED;
     685             :         }
     686             : 
     687           0 :         if (mDataSource->readAt(offset, info.mIV, IV_BYTES) < IV_BYTES) {
     688           0 :             ALOGE("couldn't read init vector");
     689           0 :             return ERROR_IO;
     690             :         }
     691           0 :         offset += IV_BYTES;
     692             : 
     693           0 :         if (size == IV_BYTES) {
     694           0 :             info.mSubsampleCount = 0;
     695           0 :             continue;
     696             :         }
     697             : 
     698           0 :         if (size < IV_BYTES + sizeof(info.mSubsampleCount)) {
     699           0 :             ALOGE("subsample count overflows sample aux info buffer");
     700           0 :             return ERROR_MALFORMED;
     701             :         }
     702             : 
     703           0 :         if (!mDataSource->getUInt16(offset, &info.mSubsampleCount)) {
     704           0 :             ALOGE("error reading sample cenc info subsample count");
     705           0 :             return ERROR_IO;
     706             :         }
     707           0 :         offset += sizeof(info.mSubsampleCount);
     708             : 
     709           0 :         if (size < IV_BYTES + sizeof(info.mSubsampleCount) + info.mSubsampleCount * 6) {
     710           0 :             ALOGE("subsample descriptions overflow sample aux info buffer");
     711           0 :             return ERROR_MALFORMED;
     712             :         }
     713             : 
     714           0 :         info.mSubsamples = new (mozilla::fallible) SampleCencInfo::SubsampleSizes[info.mSubsampleCount];
     715           0 :         if (!info.mSubsamples) {
     716           0 :           return ERROR_BUFFER_TOO_SMALL;
     717             :         }
     718           0 :         for (uint16_t j = 0; j < info.mSubsampleCount; j++) {
     719           0 :             auto& subsample = info.mSubsamples[j];
     720           0 :             if (!mDataSource->getUInt16(offset, &subsample.mClearBytes) ||
     721           0 :                 !mDataSource->getUInt32(offset + sizeof(subsample.mClearBytes),
     722             :                                         &subsample.mCipherBytes)) {
     723           0 :                 ALOGE("error reading cenc subsample aux info");
     724           0 :                 return ERROR_IO;
     725             :             }
     726           0 :             offset += 6;
     727             :         }
     728             :     }
     729             : 
     730           0 :     return OK;
     731             : }
     732             : 
     733           0 : uint32_t SampleTable::countChunkOffsets() const {
     734           0 :     return mNumChunkOffsets;
     735             : }
     736             : 
     737           0 : uint32_t SampleTable::countSamples() const {
     738           0 :     return mNumSampleSizes;
     739             : }
     740             : 
     741           0 : status_t SampleTable::getMaxSampleSize(size_t *max_size) {
     742           0 :     Mutex::Autolock autoLock(mLock);
     743             : 
     744           0 :     *max_size = 0;
     745             : 
     746           0 :     for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
     747             :         size_t sample_size;
     748           0 :         status_t err = getSampleSize_l(i, &sample_size);
     749             : 
     750           0 :         if (err != OK) {
     751           0 :             return err;
     752             :         }
     753             : 
     754           0 :         if (sample_size > *max_size) {
     755           0 :             *max_size = sample_size;
     756             :         }
     757             :     }
     758             : 
     759           0 :     return OK;
     760             : }
     761             : 
     762           0 : uint32_t abs_difference(uint32_t time1, uint32_t time2) {
     763           0 :     return time1 > time2 ? time1 - time2 : time2 - time1;
     764             : }
     765             : 
     766             : // static
     767           0 : int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
     768           0 :     const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
     769           0 :     const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
     770             : 
     771           0 :     if (a->mCompositionTime < b->mCompositionTime) {
     772           0 :         return -1;
     773           0 :     } else if (a->mCompositionTime > b->mCompositionTime) {
     774           0 :         return 1;
     775             :     }
     776             : 
     777           0 :     return 0;
     778             : }
     779             : 
     780           0 : status_t SampleTable::buildSampleEntriesTable() {
     781           0 :     Mutex::Autolock autoLock(mLock);
     782             : 
     783           0 :     if (mSampleTimeEntries != NULL) {
     784           0 :         return OK;
     785             :     }
     786             : 
     787           0 :     mSampleTimeEntries = new (mozilla::fallible) SampleTimeEntry[mNumSampleSizes];
     788           0 :     if (!mSampleTimeEntries) {
     789           0 :       return ERROR_BUFFER_TOO_SMALL;
     790             :     }
     791             : 
     792           0 :     uint32_t sampleIndex = 0;
     793           0 :     uint32_t sampleTime = 0;
     794             : 
     795           0 :     for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
     796           0 :         uint32_t n = mTimeToSample[2 * i];
     797           0 :         uint32_t delta = mTimeToSample[2 * i + 1];
     798             : 
     799           0 :         for (uint32_t j = 0; j < n; ++j) {
     800           0 :             if (sampleIndex < mNumSampleSizes) {
     801             :                 // Technically this should always be the case if the file
     802             :                 // is well-formed, but you know... there's (gasp) malformed
     803             :                 // content out there.
     804             : 
     805           0 :                 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
     806             : 
     807             :                 uint32_t compTimeDelta =
     808           0 :                     mCompositionDeltaLookup->getCompositionTimeOffset(
     809           0 :                             sampleIndex);
     810             : 
     811           0 :                 mSampleTimeEntries[sampleIndex].mCompositionTime =
     812           0 :                     sampleTime + compTimeDelta;
     813             :             }
     814             : 
     815           0 :             ++sampleIndex;
     816           0 :             sampleTime += delta;
     817             :         }
     818             :     }
     819             : 
     820           0 :     qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
     821           0 :           CompareIncreasingTime);
     822           0 :     return OK;
     823             : }
     824             : 
     825           0 : status_t SampleTable::findSampleAtTime(
     826             :         uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
     827           0 :     status_t err = buildSampleEntriesTable();
     828           0 :     if (err != OK) {
     829           0 :       return err;
     830             :     }
     831             : 
     832           0 :     uint32_t left = 0;
     833           0 :     uint32_t right = mNumSampleSizes;
     834           0 :     while (left < right) {
     835           0 :         uint32_t center = (left + right) / 2;
     836           0 :         uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
     837             : 
     838           0 :         if (req_time < centerTime) {
     839           0 :             right = center;
     840           0 :         } else if (req_time > centerTime) {
     841           0 :             left = center + 1;
     842             :         } else {
     843           0 :             left = center;
     844           0 :             break;
     845             :         }
     846             :     }
     847             : 
     848           0 :     if (left == mNumSampleSizes) {
     849           0 :         if (flags == kFlagAfter) {
     850           0 :             return ERROR_OUT_OF_RANGE;
     851             :         }
     852             : 
     853           0 :         --left;
     854             :     }
     855             : 
     856           0 :     uint32_t closestIndex = left;
     857             : 
     858           0 :     switch (flags) {
     859             :         case kFlagBefore:
     860             :         {
     861           0 :             while (closestIndex > 0
     862           0 :                     && mSampleTimeEntries[closestIndex].mCompositionTime
     863             :                             > req_time) {
     864           0 :                 --closestIndex;
     865             :             }
     866           0 :             break;
     867             :         }
     868             : 
     869             :         case kFlagAfter:
     870             :         {
     871           0 :             while (closestIndex + 1 < mNumSampleSizes
     872           0 :                     && mSampleTimeEntries[closestIndex].mCompositionTime
     873             :                             < req_time) {
     874           0 :                 ++closestIndex;
     875             :             }
     876           0 :             break;
     877             :         }
     878             : 
     879             :         default:
     880             :         {
     881           0 :             CHECK(flags == kFlagClosest);
     882             : 
     883           0 :             if (closestIndex > 0) {
     884             :                 // Check left neighbour and pick closest.
     885             :                 uint32_t absdiff1 =
     886           0 :                     abs_difference(
     887           0 :                             mSampleTimeEntries[closestIndex].mCompositionTime,
     888           0 :                             req_time);
     889             : 
     890             :                 uint32_t absdiff2 =
     891           0 :                     abs_difference(
     892           0 :                             mSampleTimeEntries[closestIndex - 1].mCompositionTime,
     893           0 :                             req_time);
     894             : 
     895           0 :                 if (absdiff1 > absdiff2) {
     896           0 :                     closestIndex = closestIndex - 1;
     897             :                 }
     898             :             }
     899             : 
     900           0 :             break;
     901             :         }
     902             :     }
     903             : 
     904           0 :     *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
     905             : 
     906           0 :     return OK;
     907             : }
     908             : 
     909           0 : status_t SampleTable::findSyncSampleNear(
     910             :         uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) {
     911           0 :     Mutex::Autolock autoLock(mLock);
     912             : 
     913           0 :     *sample_index = 0;
     914             : 
     915           0 :     if (mSyncSampleOffset < 0) {
     916             :         // All samples are sync-samples.
     917           0 :         *sample_index = start_sample_index;
     918           0 :         return OK;
     919             :     }
     920             : 
     921           0 :     if (mNumSyncSamples == 0) {
     922           0 :         *sample_index = 0;
     923           0 :         return OK;
     924             :     }
     925             : 
     926           0 :     uint32_t left = 0;
     927           0 :     uint32_t right = mNumSyncSamples;
     928           0 :     while (left < right) {
     929           0 :         uint32_t center = left + (right - left) / 2;
     930           0 :         uint32_t x = mSyncSamples[center];
     931             : 
     932           0 :         if (start_sample_index < x) {
     933           0 :             right = center;
     934           0 :         } else if (start_sample_index > x) {
     935           0 :             left = center + 1;
     936             :         } else {
     937           0 :             left = center;
     938           0 :             break;
     939             :         }
     940             :     }
     941           0 :     if (left == mNumSyncSamples) {
     942           0 :         if (flags == kFlagAfter) {
     943           0 :             ALOGE("tried to find a sync frame after the last one: %d", left);
     944           0 :             return ERROR_OUT_OF_RANGE;
     945             :         }
     946           0 :         left = left - 1;
     947             :     }
     948             : 
     949             :     // Now ssi[left] is the sync sample index just before (or at)
     950             :     // start_sample_index.
     951             :     // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples.
     952             : 
     953           0 :     uint32_t x = mSyncSamples[left];
     954             : 
     955           0 :     if (left + 1 < mNumSyncSamples) {
     956           0 :         uint32_t y = mSyncSamples[left + 1];
     957             : 
     958             :         // our sample lies between sync samples x and y.
     959             : 
     960           0 :         status_t err = mSampleIterator->seekTo(start_sample_index);
     961           0 :         if (err != OK) {
     962           0 :             return err;
     963             :         }
     964             : 
     965           0 :         uint32_t sample_time = mSampleIterator->getSampleTime();
     966             : 
     967           0 :         err = mSampleIterator->seekTo(x);
     968           0 :         if (err != OK) {
     969           0 :             return err;
     970             :         }
     971           0 :         uint32_t x_time = mSampleIterator->getSampleTime();
     972             : 
     973           0 :         err = mSampleIterator->seekTo(y);
     974           0 :         if (err != OK) {
     975           0 :             return err;
     976             :         }
     977             : 
     978           0 :         uint32_t y_time = mSampleIterator->getSampleTime();
     979             : 
     980           0 :         if (abs_difference(x_time, sample_time)
     981           0 :                 > abs_difference(y_time, sample_time)) {
     982             :             // Pick the sync sample closest (timewise) to the start-sample.
     983           0 :             x = y;
     984           0 :             ++left;
     985             :         }
     986             :     }
     987             : 
     988           0 :     switch (flags) {
     989             :         case kFlagBefore:
     990             :         {
     991           0 :             if (x > start_sample_index) {
     992           0 :                 CHECK(left > 0);
     993             : 
     994           0 :                 x = mSyncSamples[left - 1];
     995             : 
     996           0 :                 if (x > start_sample_index) {
     997             :                     // The table of sync sample indices was not sorted
     998             :                     // properly.
     999           0 :                     return ERROR_MALFORMED;
    1000             :                 }
    1001             :             }
    1002           0 :             break;
    1003             :         }
    1004             : 
    1005             :         case kFlagAfter:
    1006             :         {
    1007           0 :             if (x < start_sample_index) {
    1008           0 :                 if (left + 1 >= mNumSyncSamples) {
    1009           0 :                     return ERROR_OUT_OF_RANGE;
    1010             :                 }
    1011             : 
    1012           0 :                 x = mSyncSamples[left + 1];
    1013             : 
    1014           0 :                 if (x < start_sample_index) {
    1015             :                     // The table of sync sample indices was not sorted
    1016             :                     // properly.
    1017           0 :                     return ERROR_MALFORMED;
    1018             :                 }
    1019             :             }
    1020             : 
    1021           0 :             break;
    1022             :         }
    1023             : 
    1024             :         default:
    1025           0 :             break;
    1026             :     }
    1027             : 
    1028           0 :     *sample_index = x;
    1029             : 
    1030           0 :     return OK;
    1031             : }
    1032             : 
    1033           0 : status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
    1034           0 :     Mutex::Autolock autoLock(mLock);
    1035             : 
    1036           0 :     if (mSyncSampleOffset < 0) {
    1037             :         // All samples are sync-samples.
    1038           0 :         *sample_index = 0;
    1039           0 :         return OK;
    1040             :     }
    1041             : 
    1042           0 :     uint32_t bestSampleIndex = 0;
    1043           0 :     size_t maxSampleSize = 0;
    1044             : 
    1045             :     static const size_t kMaxNumSyncSamplesToScan = 20;
    1046             : 
    1047             :     // Consider the first kMaxNumSyncSamplesToScan sync samples and
    1048             :     // pick the one with the largest (compressed) size as the thumbnail.
    1049             : 
    1050           0 :     size_t numSamplesToScan = mNumSyncSamples;
    1051           0 :     if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
    1052           0 :         numSamplesToScan = kMaxNumSyncSamplesToScan;
    1053             :     }
    1054             : 
    1055           0 :     for (size_t i = 0; i < numSamplesToScan; ++i) {
    1056           0 :         uint32_t x = mSyncSamples[i];
    1057             : 
    1058             :         // Now x is a sample index.
    1059             :         size_t sampleSize;
    1060           0 :         status_t err = getSampleSize_l(x, &sampleSize);
    1061           0 :         if (err != OK) {
    1062           0 :             return err;
    1063             :         }
    1064             : 
    1065           0 :         if (i == 0 || sampleSize > maxSampleSize) {
    1066           0 :             bestSampleIndex = x;
    1067           0 :             maxSampleSize = sampleSize;
    1068             :         }
    1069             :     }
    1070             : 
    1071           0 :     *sample_index = bestSampleIndex;
    1072             : 
    1073           0 :     return OK;
    1074             : }
    1075             : 
    1076           0 : status_t SampleTable::getSampleSize_l(
    1077             :         uint32_t sampleIndex, size_t *sampleSize) {
    1078           0 :     return mSampleIterator->getSampleSizeDirect(
    1079           0 :             sampleIndex, sampleSize);
    1080             : }
    1081             : 
    1082           0 : status_t SampleTable::getMetaDataForSample(
    1083             :         uint32_t sampleIndex,
    1084             :         off64_t *offset,
    1085             :         size_t *size,
    1086             :         uint32_t *compositionTime,
    1087             :         uint32_t *duration,
    1088             :         bool *isSyncSample,
    1089             :         uint32_t *decodeTime) {
    1090           0 :     Mutex::Autolock autoLock(mLock);
    1091             : 
    1092             :     status_t err;
    1093           0 :     if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
    1094           0 :         return err;
    1095             :     }
    1096             : 
    1097           0 :     if (offset) {
    1098           0 :         *offset = mSampleIterator->getSampleOffset();
    1099             :     }
    1100             : 
    1101           0 :     if (size) {
    1102           0 :         *size = mSampleIterator->getSampleSize();
    1103             :     }
    1104             : 
    1105           0 :     if (compositionTime) {
    1106           0 :         *compositionTime = mSampleIterator->getSampleTime();
    1107             :     }
    1108             : 
    1109           0 :     if (decodeTime) {
    1110           0 :         *decodeTime = mSampleIterator->getSampleDecodeTime();
    1111             :     }
    1112             : 
    1113           0 :     if (duration) {
    1114           0 :         *duration = mSampleIterator->getSampleDuration();
    1115             :     }
    1116             : 
    1117           0 :     if (isSyncSample) {
    1118           0 :         *isSyncSample = false;
    1119           0 :         if (mSyncSampleOffset < 0) {
    1120             :             // Every sample is a sync sample.
    1121           0 :             *isSyncSample = true;
    1122             :         } else {
    1123           0 :             size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
    1124           0 :                     && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
    1125           0 :                 ? mLastSyncSampleIndex : 0;
    1126             : 
    1127           0 :             while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
    1128           0 :                 ++i;
    1129             :             }
    1130             : 
    1131           0 :             if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
    1132           0 :                 *isSyncSample = true;
    1133             :             }
    1134             : 
    1135           0 :             mLastSyncSampleIndex = i;
    1136             :         }
    1137             :     }
    1138             : 
    1139           0 :     return OK;
    1140             : }
    1141             : 
    1142           0 : uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
    1143           0 :     return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
    1144             : }
    1145             : 
    1146             : status_t
    1147           0 : SampleTable::getSampleCencInfo(
    1148             :         uint32_t sample_index, nsTArray<uint16_t>& clear_sizes,
    1149             :         nsTArray<uint32_t>& cipher_sizes, uint8_t iv[]) {
    1150           0 :     CHECK(clear_sizes.IsEmpty() && cipher_sizes.IsEmpty());
    1151             : 
    1152           0 :     if (sample_index >= mCencInfoCount) {
    1153           0 :         ALOGE("cenc info requested for out of range sample index");
    1154           0 :         return ERROR_MALFORMED;
    1155             :     }
    1156             : 
    1157           0 :     auto& info = mCencInfo[sample_index];
    1158           0 :     clear_sizes.SetCapacity(info.mSubsampleCount);
    1159           0 :     cipher_sizes.SetCapacity(info.mSubsampleCount);
    1160             : 
    1161           0 :     for (uint32_t i = 0; i < info.mSubsampleCount; i++) {
    1162           0 :         clear_sizes.AppendElement(info.mSubsamples[i].mClearBytes);
    1163           0 :         cipher_sizes.AppendElement(info.mSubsamples[i].mCipherBytes);
    1164             :     }
    1165             : 
    1166           0 :     memcpy(iv, info.mIV, IV_BYTES);
    1167             : 
    1168           0 :     return OK;
    1169             : }
    1170             : 
    1171             : }  // namespace stagefright
    1172             : 
    1173             : #undef LOG_TAG

Generated by: LCOV version 1.13