FileSource.cpp revision c7fc37a3dab9bd1f96713649f351b5990e6316ff
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#include <media/stagefright/FileSource.h>
18#include <media/stagefright/MediaDebug.h>
19#include <sys/types.h>
20#include <unistd.h>
21
22namespace android {
23
24FileSource::FileSource(const char *filename)
25    : mFile(fopen(filename, "rb")),
26      mFd(mFile == NULL ? -1 : fileno(mFile)),
27      mOffset(0),
28      mLength(-1),
29      mDecryptHandle(NULL),
30      mDrmManagerClient(NULL),
31      mDrmBufOffset(0),
32      mDrmBufSize(0),
33      mDrmBuf(NULL){
34}
35
36FileSource::FileSource(int fd, int64_t offset, int64_t length)
37    : mFile(fdopen(fd, "rb")),
38      mFd(fd),
39      mOffset(offset),
40      mLength(length),
41      mDecryptHandle(NULL),
42      mDrmManagerClient(NULL),
43      mDrmBufOffset(0),
44      mDrmBufSize(0),
45      mDrmBuf(NULL){
46    CHECK(offset >= 0);
47    CHECK(length >= 0);
48}
49
50FileSource::~FileSource() {
51    if (mFile != NULL) {
52        fclose(mFile);
53        mFile = NULL;
54    }
55
56    if (mDrmBuf != NULL) {
57        delete[] mDrmBuf;
58        mDrmBuf = NULL;
59    }
60}
61
62status_t FileSource::initCheck() const {
63    return mFile != NULL ? OK : NO_INIT;
64}
65
66ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
67    if (mFile == NULL) {
68        return NO_INIT;
69    }
70
71    Mutex::Autolock autoLock(mLock);
72
73    if (mLength >= 0) {
74        if (offset >= mLength) {
75            return 0;  // read beyond EOF.
76        }
77        int64_t numAvailable = mLength - offset;
78        if ((int64_t)size > numAvailable) {
79            size = numAvailable;
80        }
81    }
82
83    if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
84            == mDecryptHandle->decryptApiType) {
85        return readAtDRM(offset, data, size);
86   } else {
87        off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
88        if (result == -1) {
89            LOGE("seek to %lld failed", offset + mOffset);
90            return UNKNOWN_ERROR;
91        }
92
93        return ::read(mFd, data, size);
94    }
95}
96
97status_t FileSource::getSize(off64_t *size) {
98    if (mFile == NULL) {
99        return NO_INIT;
100    }
101
102    if (mLength >= 0) {
103        *size = mLength;
104
105        return OK;
106    }
107
108    *size = lseek64(mFd, 0, SEEK_END);
109
110    return OK;
111}
112
113DecryptHandle* FileSource::DrmInitialization(DrmManagerClient* client) {
114    if (client == NULL) {
115        return NULL;
116    }
117    mDrmManagerClient = client;
118
119    if (mDecryptHandle == NULL) {
120        mDecryptHandle = mDrmManagerClient->openDecryptSession(
121                mFd, mOffset, mLength);
122    }
123
124    if (mDecryptHandle == NULL) {
125        mDrmManagerClient = NULL;
126    }
127
128    return mDecryptHandle;
129}
130
131void FileSource::getDrmInfo(DecryptHandle **handle, DrmManagerClient **client) {
132    *handle = mDecryptHandle;
133
134    *client = mDrmManagerClient;
135}
136
137ssize_t FileSource::readAtDRM(off64_t offset, void *data, size_t size) {
138    size_t DRM_CACHE_SIZE = 1024;
139    if (mDrmBuf == NULL) {
140        mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
141    }
142
143    if (mDrmBuf != NULL && mDrmBufSize > 0 && (offset + mOffset) >= mDrmBufOffset
144            && (offset + mOffset + size) <= (mDrmBufOffset + mDrmBufSize)) {
145        /* Use buffered data */
146        memcpy(data, (void*)(mDrmBuf+(offset+mOffset-mDrmBufOffset)), size);
147        return size;
148    } else if (size <= DRM_CACHE_SIZE) {
149        /* Buffer new data */
150        mDrmBufOffset =  offset + mOffset;
151        mDrmBufSize = mDrmManagerClient->pread(mDecryptHandle, mDrmBuf,
152                DRM_CACHE_SIZE, offset + mOffset);
153        if (mDrmBufSize > 0) {
154            int64_t dataRead = 0;
155            dataRead = size > mDrmBufSize ? mDrmBufSize : size;
156            memcpy(data, (void*)mDrmBuf, dataRead);
157            return dataRead;
158        } else {
159            return mDrmBufSize;
160        }
161    } else {
162        /* Too big chunk to cache. Call DRM directly */
163        return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset);
164    }
165}
166}  // namespace android
167