TimedTextDriver.cpp revision d411b4ca2945cd8974a3a78199fce94646950128
1 /*
2 * Copyright (C) 2012 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 "TimedTextDriver"
19#include <utils/Log.h>
20
21#include <binder/IPCThreadState.h>
22
23#include <media/mediaplayer.h>
24#include <media/MediaPlayerInterface.h>
25#include <media/stagefright/DataSource.h>
26#include <media/stagefright/FileSource.h>
27#include <media/stagefright/MediaDefs.h>
28#include <media/stagefright/MediaErrors.h>
29#include <media/stagefright/MediaSource.h>
30#include <media/stagefright/MetaData.h>
31#include <media/stagefright/Utils.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <media/stagefright/foundation/ALooper.h>
34#include <media/stagefright/timedtext/TimedTextDriver.h>
35
36#include "TextDescriptions.h"
37#include "TimedTextPlayer.h"
38#include "TimedTextSource.h"
39
40namespace android {
41
42TimedTextDriver::TimedTextDriver(
43        const wp<MediaPlayerBase> &listener)
44    : mLooper(new ALooper),
45      mListener(listener),
46      mHTTPService(httpService),
47      mState(UNINITIALIZED),
48      mCurrentTrackIndex(UINT_MAX) {
49    mLooper->setName("TimedTextDriver");
50    mLooper->start();
51    mPlayer = new TimedTextPlayer(listener);
52    mLooper->registerHandler(mPlayer);
53}
54
55TimedTextDriver::~TimedTextDriver() {
56    mTextSourceVector.clear();
57    mTextSourceTypeVector.clear();
58    mLooper->stop();
59}
60
61status_t TimedTextDriver::selectTrack_l(size_t index) {
62    if (mCurrentTrackIndex == index) {
63        return OK;
64    }
65    sp<TimedTextSource> source;
66    source = mTextSourceVector.valueFor(index);
67    mPlayer->setDataSource(source);
68    if (mState == UNINITIALIZED) {
69        mState = PREPARED;
70    }
71    mCurrentTrackIndex = index;
72    return OK;
73}
74
75status_t TimedTextDriver::start() {
76    Mutex::Autolock autoLock(mLock);
77    switch (mState) {
78        case UNINITIALIZED:
79            return INVALID_OPERATION;
80        case PLAYING:
81            return OK;
82        case PREPARED:
83            mPlayer->start();
84            mState = PLAYING;
85            return OK;
86        case PAUSED:
87            mPlayer->resume();
88            mState = PLAYING;
89            return OK;
90        default:
91            TRESPASS();
92    }
93    return UNKNOWN_ERROR;
94}
95
96status_t TimedTextDriver::pause() {
97    Mutex::Autolock autoLock(mLock);
98    ALOGV("%s() is called", __FUNCTION__);
99    switch (mState) {
100        case UNINITIALIZED:
101            return INVALID_OPERATION;
102        case PLAYING:
103            mPlayer->pause();
104            mState = PAUSED;
105            return OK;
106        case PREPARED:
107            return INVALID_OPERATION;
108        case PAUSED:
109            return OK;
110        default:
111            TRESPASS();
112    }
113    return UNKNOWN_ERROR;
114}
115
116status_t TimedTextDriver::selectTrack(size_t index) {
117    status_t ret = OK;
118    Mutex::Autolock autoLock(mLock);
119    ALOGV("%s() is called", __FUNCTION__);
120    switch (mState) {
121        case UNINITIALIZED:
122        case PREPARED:
123        case PAUSED:
124            ret = selectTrack_l(index);
125            break;
126        case PLAYING:
127            mPlayer->pause();
128            ret = selectTrack_l(index);
129            if (ret != OK) {
130                break;
131            }
132            mPlayer->start();
133            break;
134        defaut:
135            TRESPASS();
136    }
137    return ret;
138}
139
140status_t TimedTextDriver::unselectTrack(size_t index) {
141    Mutex::Autolock autoLock(mLock);
142    ALOGV("%s() is called", __FUNCTION__);
143    if (mCurrentTrackIndex != index) {
144        return INVALID_OPERATION;
145    }
146    mCurrentTrackIndex = UINT_MAX;
147    switch (mState) {
148        case UNINITIALIZED:
149            return INVALID_OPERATION;
150        case PLAYING:
151            mPlayer->setDataSource(NULL);
152            mState = UNINITIALIZED;
153            return OK;
154        case PREPARED:
155        case PAUSED:
156            mState = UNINITIALIZED;
157            return OK;
158        default:
159            TRESPASS();
160    }
161    return UNKNOWN_ERROR;
162}
163
164status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
165    Mutex::Autolock autoLock(mLock);
166    ALOGV("%s() is called", __FUNCTION__);
167    switch (mState) {
168        case UNINITIALIZED:
169            return INVALID_OPERATION;
170        case PREPARED:
171            mPlayer->seekToAsync(timeUs);
172            mPlayer->pause();
173            mState = PAUSED;
174            return OK;
175        case PAUSED:
176            mPlayer->seekToAsync(timeUs);
177            mPlayer->pause();
178            return OK;
179        case PLAYING:
180            mPlayer->seekToAsync(timeUs);
181            return OK;
182        defaut:
183            TRESPASS();
184    }
185    return UNKNOWN_ERROR;
186}
187
188status_t TimedTextDriver::addInBandTextSource(
189        size_t trackIndex, const sp<MediaSource>& mediaSource) {
190    sp<TimedTextSource> source =
191            TimedTextSource::CreateTimedTextSource(mediaSource);
192    if (source == NULL) {
193        return ERROR_UNSUPPORTED;
194    }
195    Mutex::Autolock autoLock(mLock);
196    mTextSourceVector.add(trackIndex, source);
197    mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_IN_BAND);
198    return OK;
199}
200
201status_t TimedTextDriver::addOutOfBandTextSource(
202        size_t trackIndex, const char *uri, const char *mimeType) {
203
204    // To support local subtitle file only for now
205    if (strncasecmp("file://", uri, 7)) {
206        ALOGE("uri('%s') is not a file", uri);
207        return ERROR_UNSUPPORTED;
208    }
209
210    sp<DataSource> dataSource =
211            DataSource::CreateFromURI(uri);
212    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
213}
214
215status_t TimedTextDriver::addOutOfBandTextSource(
216        size_t trackIndex, int fd, off64_t offset, off64_t length, const char *mimeType) {
217
218    if (fd < 0) {
219        ALOGE("Invalid file descriptor: %d", fd);
220        return ERROR_UNSUPPORTED;
221    }
222
223    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
224    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
225}
226
227status_t TimedTextDriver::createOutOfBandTextSource(
228        size_t trackIndex,
229        const char *mimeType,
230        const sp<DataSource>& dataSource) {
231
232    if (dataSource == NULL) {
233        return ERROR_UNSUPPORTED;
234    }
235
236    sp<TimedTextSource> source;
237    if (strcasecmp(mimeType, MEDIA_MIMETYPE_TEXT_SUBRIP) == 0) {
238        source = TimedTextSource::CreateTimedTextSource(
239                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
240    }
241
242    if (source == NULL) {
243        ALOGE("Failed to create timed text source");
244        return ERROR_UNSUPPORTED;
245    }
246
247    Mutex::Autolock autoLock(mLock);
248    mTextSourceVector.add(trackIndex, source);
249    mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_OUT_OF_BAND);
250    return OK;
251}
252
253size_t TimedTextDriver::countExternalTracks() const {
254    size_t nTracks = 0;
255    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
256        if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_OUT_OF_BAND) {
257            ++nTracks;
258        }
259    }
260    return nTracks;
261}
262
263void TimedTextDriver::getExternalTrackInfo(Parcel *parcel) {
264    Mutex::Autolock autoLock(mLock);
265    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
266        if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_IN_BAND) {
267            continue;
268        }
269
270        sp<MetaData> meta = mTextSourceVector.valueAt(i)->getFormat();
271
272        // There are two fields.
273        parcel->writeInt32(2);
274
275        // track type.
276        parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
277        const char *lang = "und";
278        if (meta != NULL) {
279            meta->findCString(kKeyMediaLanguage, &lang);
280        }
281        parcel->writeString16(String16(lang));
282    }
283}
284
285}  // namespace android
286