Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright 2015 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 "CallbackDataSource"
     19 #include <utils/Log.h>
     20 
     21 #include "include/CallbackDataSource.h"
     22 
     23 #include <binder/IMemory.h>
     24 #include <media/IDataSource.h>
     25 #include <media/stagefright/foundation/ADebug.h>
     26 
     27 #include <algorithm>
     28 
     29 namespace android {
     30 
     31 CallbackDataSource::CallbackDataSource(
     32     const sp<IDataSource>& binderDataSource)
     33     : mIDataSource(binderDataSource),
     34       mIsClosed(false) {
     35     // Set up the buffer to read into.
     36     mMemory = mIDataSource->getIMemory();
     37     mName = String8::format("CallbackDataSource(%s)", mIDataSource->toString().string());
     38 
     39 }
     40 
     41 CallbackDataSource::~CallbackDataSource() {
     42     ALOGV("~CallbackDataSource");
     43     close();
     44 }
     45 
     46 status_t CallbackDataSource::initCheck() const {
     47     if (mMemory == NULL) {
     48         return UNKNOWN_ERROR;
     49     }
     50     return OK;
     51 }
     52 
     53 ssize_t CallbackDataSource::readAt(off64_t offset, void* data, size_t size) {
     54     if (mMemory == NULL || data == NULL) {
     55         return -1;
     56     }
     57 
     58     // IDataSource can only read up to mMemory->size() bytes at a time, but this
     59     // method should be able to read any number of bytes, so read in a loop.
     60     size_t totalNumRead = 0;
     61     size_t numLeft = size;
     62     const size_t bufferSize = mMemory->size();
     63 
     64     while (numLeft > 0) {
     65         size_t numToRead = std::min(numLeft, bufferSize);
     66         ssize_t numRead =
     67             mIDataSource->readAt(offset + totalNumRead, numToRead);
     68         // A negative return value represents an error. Pass it on.
     69         if (numRead < 0) {
     70             return numRead == ERROR_END_OF_STREAM && totalNumRead > 0 ? totalNumRead : numRead;
     71         }
     72         // A zero return value signals EOS. Return the bytes read so far.
     73         if (numRead == 0) {
     74             return totalNumRead;
     75         }
     76         if ((size_t)numRead > numToRead) {
     77             return ERROR_OUT_OF_RANGE;
     78         }
     79         CHECK(numRead >= 0 && (size_t)numRead <= bufferSize);
     80         memcpy(((uint8_t*)data) + totalNumRead, mMemory->pointer(), numRead);
     81         numLeft -= numRead;
     82         totalNumRead += numRead;
     83     }
     84 
     85     return totalNumRead;
     86 }
     87 
     88 status_t CallbackDataSource::getSize(off64_t *size) {
     89     status_t err = mIDataSource->getSize(size);
     90     if (err != OK) {
     91         return err;
     92     }
     93     if (*size < 0) {
     94         // IDataSource will set size to -1 to indicate unknown size, but
     95         // DataSource returns ERROR_UNSUPPORTED for that.
     96         return ERROR_UNSUPPORTED;
     97     }
     98     return OK;
     99 }
    100 
    101 uint32_t CallbackDataSource::flags() {
    102     return mIDataSource->getFlags();
    103 }
    104 
    105 void CallbackDataSource::close() {
    106     if (!mIsClosed) {
    107         mIDataSource->close();
    108         mIsClosed = true;
    109     }
    110 }
    111 
    112 sp<DecryptHandle> CallbackDataSource::DrmInitialization(const char *mime) {
    113     return mIDataSource->DrmInitialization(mime);
    114 }
    115 
    116 sp<IDataSource> CallbackDataSource::getIDataSource() const {
    117     return mIDataSource;
    118 }
    119 
    120 TinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
    121     : mSource(source), mCachedOffset(0), mCachedSize(0) {
    122     mName = String8::format("TinyCacheSource(%s)", mSource->toString().string());
    123 }
    124 
    125 status_t TinyCacheSource::initCheck() const {
    126     return mSource->initCheck();
    127 }
    128 
    129 ssize_t TinyCacheSource::readAt(off64_t offset, void* data, size_t size) {
    130     // Check if the cache satisfies the read.
    131     if (mCachedOffset <= offset
    132             && offset < (off64_t) (mCachedOffset + mCachedSize)) {
    133         if (offset + size <= mCachedOffset + mCachedSize) {
    134             memcpy(data, &mCache[offset - mCachedOffset], size);
    135             return size;
    136         } else {
    137             // If the cache hits only partially, flush the cache and read the
    138             // remainder.
    139 
    140             // This value is guaranteed to be greater than 0 because of the
    141             // enclosing if statement.
    142             const ssize_t remaining = mCachedOffset + mCachedSize - offset;
    143             memcpy(data, &mCache[offset - mCachedOffset], remaining);
    144             const ssize_t readMore = readAt(offset + remaining,
    145                     (uint8_t*)data + remaining, size - remaining);
    146             if (readMore < 0) {
    147                 return readMore;
    148             }
    149             return remaining + readMore;
    150         }
    151     }
    152 
    153     if (size >= kCacheSize) {
    154         return mSource->readAt(offset, data, size);
    155     }
    156 
    157     // Fill the cache and copy to the caller.
    158     const ssize_t numRead = mSource->readAt(offset, mCache, kCacheSize);
    159     if (numRead <= 0) {
    160         // Flush cache on error
    161         mCachedSize = 0;
    162         mCachedOffset = 0;
    163         return numRead;
    164     }
    165     if ((size_t)numRead > kCacheSize) {
    166         // Flush cache on error
    167         mCachedSize = 0;
    168         mCachedOffset = 0;
    169         return ERROR_OUT_OF_RANGE;
    170     }
    171 
    172     mCachedSize = numRead;
    173     mCachedOffset = offset;
    174     CHECK(mCachedSize <= kCacheSize && mCachedOffset >= 0);
    175     const size_t numToReturn = std::min(size, (size_t)numRead);
    176     memcpy(data, mCache, numToReturn);
    177 
    178     return numToReturn;
    179 }
    180 
    181 status_t TinyCacheSource::getSize(off64_t *size) {
    182     return mSource->getSize(size);
    183 }
    184 
    185 uint32_t TinyCacheSource::flags() {
    186     return mSource->flags();
    187 }
    188 
    189 sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
    190     // flush cache when DrmInitialization occurs since decrypted
    191     // data may differ from what is in cache.
    192     mCachedOffset = 0;
    193     mCachedSize = 0;
    194     return mSource->DrmInitialization(mime);
    195 }
    196 
    197 sp<IDataSource> TinyCacheSource::getIDataSource() const {
    198     return mSource->getIDataSource();
    199 }
    200 
    201 } // namespace android
    202