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     if (size >= kCacheSize) {
    131         return mSource->readAt(offset, data, size);
    132     }
    133 
    134     // Check if the cache satisfies the read.
    135     if (mCachedOffset <= offset
    136             && offset < (off64_t) (mCachedOffset + mCachedSize)) {
    137         if (offset + size <= mCachedOffset + mCachedSize) {
    138             memcpy(data, &mCache[offset - mCachedOffset], size);
    139             return size;
    140         } else {
    141             // If the cache hits only partially, flush the cache and read the
    142             // remainder.
    143 
    144             // This value is guaranteed to be greater than 0 because of the
    145             // enclosing if statement.
    146             const ssize_t remaining = mCachedOffset + mCachedSize - offset;
    147             memcpy(data, &mCache[offset - mCachedOffset], remaining);
    148             const ssize_t readMore = readAt(offset + remaining,
    149                     (uint8_t*)data + remaining, size - remaining);
    150             if (readMore < 0) {
    151                 return readMore;
    152             }
    153             return remaining + readMore;
    154         }
    155     }
    156 
    157 
    158     // Fill the cache and copy to the caller.
    159     const ssize_t numRead = mSource->readAt(offset, mCache, kCacheSize);
    160     if (numRead <= 0) {
    161         // Flush cache on error
    162         mCachedSize = 0;
    163         mCachedOffset = 0;
    164         return numRead;
    165     }
    166     if ((size_t)numRead > kCacheSize) {
    167         // Flush cache on error
    168         mCachedSize = 0;
    169         mCachedOffset = 0;
    170         return ERROR_OUT_OF_RANGE;
    171     }
    172 
    173     mCachedSize = numRead;
    174     mCachedOffset = offset;
    175     CHECK(mCachedSize <= kCacheSize && mCachedOffset >= 0);
    176     const size_t numToReturn = std::min(size, (size_t)numRead);
    177     memcpy(data, mCache, numToReturn);
    178 
    179     return numToReturn;
    180 }
    181 
    182 status_t TinyCacheSource::getSize(off64_t *size) {
    183     return mSource->getSize(size);
    184 }
    185 
    186 uint32_t TinyCacheSource::flags() {
    187     return mSource->flags();
    188 }
    189 
    190 sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
    191     // flush cache when DrmInitialization occurs since decrypted
    192     // data may differ from what is in cache.
    193     mCachedOffset = 0;
    194     mCachedSize = 0;
    195     return mSource->DrmInitialization(mime);
    196 }
    197 
    198 sp<IDataSource> TinyCacheSource::getIDataSource() const {
    199     return mSource->getIDataSource();
    200 }
    201 
    202 } // namespace android
    203