CallbackDataSource.cpp revision 69d3d8a9540b0da787ea0beccad2517f057dd54d
165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/*
2d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * Copyright 2015 The Android Open Source Project
3d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk *
4d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * you may not use this file except in compliance with the License.
6d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * You may obtain a copy of the License at
7d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk *
8d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk *
10d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * Unless required by applicable law or agreed to in writing, software
11d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * See the License for the specific language governing permissions and
14d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk * limitations under the License.
15d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk */
1665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian//#define LOG_NDEBUG 0
18a84bbe6b59721b1b963d65d270aa98d6513bbb78Eino-Ville Talvala#define LOG_TAG "CallbackDataSource"
198951a97b1f8462c37e740ea5082eea0445d2c501Iliyan Malchev#include <utils/Log.h>
2065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
21cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk#include "include/CallbackDataSource.h"
22cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
2365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <binder/IMemory.h>
24cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk#include <media/IDataSource.h>
25cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk#include <media/stagefright/foundation/ADebug.h>
26cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
2765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <algorithm>
28cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
2965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android {
3065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
31d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville TalvalaCallbackDataSource::CallbackDataSource(
32d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    const sp<IDataSource>& binderDataSource)
33d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    : mIDataSource(binderDataSource),
349c2a2c26c0d70de97f51063b06a5efc79b327eedAlex Deymo      mIsClosed(false) {
35ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    // Set up the buffer to read into.
3665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mMemory = mIDataSource->getIMemory();
3765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mName = String8::format("CallbackDataSource(%s)", mIDataSource->toString().string());
3865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
3965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
40cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
4165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianCallbackDataSource::~CallbackDataSource() {
42b5ca4618a722a21f084fe8bfc1c2992749ccd3f0Nipun Kwatra    ALOGV("~CallbackDataSource");
43df712ea86e6350f7005a02ab0e1c60c28a343ed0Mathias Agopian    close();
4465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
45d89821ec5481e0640d84bfe3e29a1254a52ca683Eino-Ville Talvala
4665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianstatus_t CallbackDataSource::initCheck() const {
471b86fe063badb5f28c467ade39be0f4008688947Andreas Huber    if (mMemory == NULL) {
4865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        return UNKNOWN_ERROR;
4999e69716215cd0665379bc90d708f2ea8689831dRuben Brunk    }
5065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return OK;
5165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
5265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
53d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunkssize_t CallbackDataSource::readAt(off64_t offset, void* data, size_t size) {
5498a668f6ea51e4d894d2ebb61a0e18287fb14008Chien-Yu Chen    if (mMemory == NULL) {
55d1176ef16677b6c94fb893edb6a864cdccc0b190Ruben Brunk        return -1;
56b2119af7f4ced0ecfefd4c7388f86b4e3a3ea7d8Ruben Brunk    }
57b2119af7f4ced0ecfefd4c7388f86b4e3a3ea7d8Ruben Brunk
5865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // IDataSource can only read up to mMemory->size() bytes at a time, but this
5965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // method should be able to read any number of bytes, so read in a loop.
607b82efe7a376c882f8f938e1c41b8311a8cdda4aEino-Ville Talvala    size_t totalNumRead = 0;
617b82efe7a376c882f8f938e1c41b8311a8cdda4aEino-Ville Talvala    size_t numLeft = size;
627b82efe7a376c882f8f938e1c41b8311a8cdda4aEino-Ville Talvala    const size_t bufferSize = mMemory->size();
63ff3e31d2b100d8efd969b358b18e4405c49dd10dIgor Murashkin
6465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    while (numLeft > 0) {
650dea57fd9fc4b2ccaab97d9477359fbd5a626f5cYin-Chia Yeh        size_t numToRead = std::min(numLeft, bufferSize);
660dea57fd9fc4b2ccaab97d9477359fbd5a626f5cYin-Chia Yeh        ssize_t numRead =
670dea57fd9fc4b2ccaab97d9477359fbd5a626f5cYin-Chia Yeh            mIDataSource->readAt(offset + totalNumRead, numToRead);
680dea57fd9fc4b2ccaab97d9477359fbd5a626f5cYin-Chia Yeh        // A negative return value represents an error. Pass it on.
6965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        if (numRead < 0) {
7065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            return numRead == ERROR_END_OF_STREAM && totalNumRead > 0 ? totalNumRead : numRead;
71d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        }
72d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        // A zero return value signals EOS. Return the bytes read so far.
73d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        if (numRead == 0) {
7465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            return totalNumRead;
7565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
7665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        if ((size_t)numRead > numToRead) {
775e08d60617fc63c2e41f9069ff89f5c00db2617dEino-Ville Talvala            return ERROR_OUT_OF_RANGE;
7865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
79b8a805261bf0282e992d3608035e47d05a898710Steve Block        CHECK(numRead >= 0 && (size_t)numRead <= bufferSize);
80b8a805261bf0282e992d3608035e47d05a898710Steve Block        memcpy(((uint8_t*)data) + totalNumRead, mMemory->pointer(), numRead);
8165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        numLeft -= numRead;
8265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        totalNumRead += numRead;
8365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
8465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
8565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return totalNumRead;
86d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala}
87d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala
88d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvalastatus_t CallbackDataSource::getSize(off64_t *size) {
89d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    status_t err = mIDataSource->getSize(size);
90d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    if (err != OK) {
91d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        return err;
92d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    }
93d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    if (*size < 0) {
94d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        // IDataSource will set size to -1 to indicate unknown size, but
95d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        // DataSource returns ERROR_UNSUPPORTED for that.
96d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        return ERROR_UNSUPPORTED;
9765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
9865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return OK;
99cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin}
100cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin
101cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkinuint32_t CallbackDataSource::flags() {
102cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin    return mIDataSource->getFlags();
103cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin}
104cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin
105cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunkvoid CallbackDataSource::close() {
106cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin    if (!mIsClosed) {
107e16d1165c5dccfb44753610f39b120938269cd3aBin Chen        mIDataSource->close();
108cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        mIsClosed = true;
109cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin    }
1103068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen}
1113068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen
1123068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu ChenTinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
1133068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen    : mSource(source), mCachedOffset(0), mCachedSize(0) {
1143068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen    mName = String8::format("TinyCacheSource(%s)", mSource->toString().string());
1153068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen}
1163068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen
1173068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chenstatus_t TinyCacheSource::initCheck() const {
1183068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen    return mSource->initCheck();
1193068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen}
1203068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen
1213068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chenssize_t TinyCacheSource::readAt(off64_t offset, void* data, size_t size) {
122d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    if (size >= kCacheSize) {
1233068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen        return mSource->readAt(offset, data, size);
12488da526d97442c80731e01bfc94c6b47c4b0c3c7Chien-Yu Chen    }
1253068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen
1263068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen    // Check if the cache satisfies the read.
12788da526d97442c80731e01bfc94c6b47c4b0c3c7Chien-Yu Chen    if (mCachedOffset <= offset
12888da526d97442c80731e01bfc94c6b47c4b0c3c7Chien-Yu Chen            && offset < (off64_t) (mCachedOffset + mCachedSize)) {
12988da526d97442c80731e01bfc94c6b47c4b0c3c7Chien-Yu Chen        if (offset + size <= mCachedOffset + mCachedSize) {
13088da526d97442c80731e01bfc94c6b47c4b0c3c7Chien-Yu Chen            memcpy(data, &mCache[offset - mCachedOffset], size);
13188da526d97442c80731e01bfc94c6b47c4b0c3c7Chien-Yu Chen            return size;
1323068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen        } else {
1333068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen            // If the cache hits only partially, flush the cache and read the
1343068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen            // remainder.
1353068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen
1363068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen            // This value is guaranteed to be greater than 0 because of the
1373068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen            // enclosing if statement.
1383068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen            const ssize_t remaining = mCachedOffset + mCachedSize - offset;
13988da526d97442c80731e01bfc94c6b47c4b0c3c7Chien-Yu Chen            memcpy(data, &mCache[offset - mCachedOffset], remaining);
1403068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen            const ssize_t readMore = readAt(offset + remaining,
1413068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen                    (uint8_t*)data + remaining, size - remaining);
142cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin            if (readMore < 0) {
143cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin                return readMore;
14465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            }
14565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            return remaining + readMore;
14665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
14765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
14865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
14965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // Fill the cache and copy to the caller.
15049c9705a7987b94bd53fddd4834f5f534cf946f7Eino-Ville Talvala    const ssize_t numRead = mSource->readAt(offset, mCache, kCacheSize);
15149c9705a7987b94bd53fddd4834f5f534cf946f7Eino-Ville Talvala    if (numRead <= 0) {
152d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala        return numRead;
153d56db1d2bee182d1851097a9c712712fc094d117Eino-Ville Talvala    }
154df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    if ((size_t)numRead > kCacheSize) {
1558951a97b1f8462c37e740ea5082eea0445d2c501Iliyan Malchev        return ERROR_OUT_OF_RANGE;
156bfc9915f482520eb9676c6d2dbf7f1ac078d937dIgor Murashkin    }
157cba2c163555cd329f49d40658ea3ee902e94dda3Igor Murashkin
1583068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen    mCachedSize = numRead;
1593068d73c6c7e1f44523b1466b903a9c82408b258Chien-Yu Chen    mCachedOffset = offset;
160cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    CHECK(mCachedSize <= kCacheSize && mCachedOffset >= 0);
1618951a97b1f8462c37e740ea5082eea0445d2c501Iliyan Malchev    const size_t numToReturn = std::min(size, (size_t)numRead);
16265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    memcpy(data, mCache, numToReturn);
1638951a97b1f8462c37e740ea5082eea0445d2c501Iliyan Malchev
1648951a97b1f8462c37e740ea5082eea0445d2c501Iliyan Malchev    return numToReturn;
165cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk}
166634a51509ee50475f3e9f8ccf897e90fc72ded31Igor Murashkin
1678951a97b1f8462c37e740ea5082eea0445d2c501Iliyan Malchevstatus_t TinyCacheSource::getSize(off64_t *size) {
16865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return mSource->getSize(size);
16999e69716215cd0665379bc90d708f2ea8689831dRuben Brunk}
17099e69716215cd0665379bc90d708f2ea8689831dRuben Brunk
17199e69716215cd0665379bc90d708f2ea8689831dRuben Brunkuint32_t TinyCacheSource::flags() {
17299e69716215cd0665379bc90d708f2ea8689831dRuben Brunk    return mSource->flags();
17399e69716215cd0665379bc90d708f2ea8689831dRuben Brunk}
174e074a93046ebe5cea0b55c3a479e082a426e1e07Yin-Chia Yeh
1751527f07eb2b2b40f6b8f53a4644e6a400bddb460Eino-Ville Talvala} // namespace android
1761527f07eb2b2b40f6b8f53a4644e6a400bddb460Eino-Ville Talvala