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