TimedTextDriver.cpp revision 3254b25e8b0f674ccc2226609e01dd86a600802e
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/MediaPlayerInterface.h>
24#include <media/stagefright/MediaErrors.h>
25#include <media/stagefright/MediaSource.h>
26#include <media/stagefright/DataSource.h>
27#include <media/stagefright/Utils.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/ALooper.h>
30#include <media/stagefright/timedtext/TimedTextDriver.h>
31
32#include "TextDescriptions.h"
33#include "TimedTextPlayer.h"
34#include "TimedTextSource.h"
35
36namespace android {
37
38TimedTextDriver::TimedTextDriver(
39        const wp<MediaPlayerBase> &listener)
40    : mLooper(new ALooper),
41      mListener(listener),
42      mState(UNINITIALIZED) {
43    mLooper->setName("TimedTextDriver");
44    mLooper->start();
45    mPlayer = new TimedTextPlayer(listener);
46    mLooper->registerHandler(mPlayer);
47}
48
49TimedTextDriver::~TimedTextDriver() {
50    mTextInBandVector.clear();
51    mTextOutOfBandVector.clear();
52    mLooper->stop();
53}
54
55status_t TimedTextDriver::setTimedTextTrackIndex_l(int32_t index) {
56    if (index >=
57            (int)(mTextInBandVector.size() + mTextOutOfBandVector.size())) {
58        return BAD_VALUE;
59    }
60
61    sp<TimedTextSource> source;
62    if (index < mTextInBandVector.size()) {
63        source = mTextInBandVector.itemAt(index);
64    } else {
65        source = mTextOutOfBandVector.itemAt(index - mTextInBandVector.size());
66    }
67    mPlayer->setDataSource(source);
68    return OK;
69}
70
71status_t TimedTextDriver::start() {
72    Mutex::Autolock autoLock(mLock);
73    switch (mState) {
74        case UNINITIALIZED:
75            return INVALID_OPERATION;
76        case STOPPED:
77            mPlayer->start();
78            break;
79        case PLAYING:
80            return OK;
81        case PAUSED:
82            mPlayer->resume();
83            break;
84        default:
85            TRESPASS();
86    }
87    mState = PLAYING;
88    return OK;
89}
90
91status_t TimedTextDriver::stop() {
92    return pause();
93}
94
95// TODO: Test if pause() works properly.
96// Scenario 1: start - pause - resume
97// Scenario 2: start - seek
98// Scenario 3: start - pause - seek - resume
99status_t TimedTextDriver::pause() {
100    Mutex::Autolock autoLock(mLock);
101    switch (mState) {
102        case UNINITIALIZED:
103            return INVALID_OPERATION;
104        case STOPPED:
105            return OK;
106        case PLAYING:
107            mPlayer->pause();
108            break;
109        case PAUSED:
110            return OK;
111        default:
112            TRESPASS();
113    }
114    mState = PAUSED;
115    return OK;
116}
117
118status_t TimedTextDriver::resume() {
119    return start();
120}
121
122status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
123    mPlayer->seekToAsync(timeUs);
124    return OK;
125}
126
127status_t TimedTextDriver::setTimedTextTrackIndex(int32_t index) {
128    // TODO: This is current implementation for MediaPlayer::disableTimedText().
129    // Find better way for readability.
130    if (index < 0) {
131        mPlayer->pause();
132        return OK;
133    }
134
135    status_t ret = OK;
136    Mutex::Autolock autoLock(mLock);
137    switch (mState) {
138        case UNINITIALIZED:
139            ret = INVALID_OPERATION;
140            break;
141        case PAUSED:
142            ret = setTimedTextTrackIndex_l(index);
143            break;
144        case PLAYING:
145            mPlayer->pause();
146            ret = setTimedTextTrackIndex_l(index);
147            if (ret != OK) {
148                break;
149            }
150            mPlayer->start();
151            break;
152        case STOPPED:
153            // TODO: The only difference between STOPPED and PAUSED is this
154            // part. Revise the flow from "MediaPlayer::enableTimedText()" and
155            // remove one of the status, PAUSED and STOPPED, if possible.
156            ret = setTimedTextTrackIndex_l(index);
157            if (ret != OK) {
158                break;
159            }
160            mPlayer->start();
161            break;
162        defaut:
163            TRESPASS();
164    }
165    return ret;
166}
167
168status_t TimedTextDriver::addInBandTextSource(
169        const sp<MediaSource>& mediaSource) {
170    sp<TimedTextSource> source =
171            TimedTextSource::CreateTimedTextSource(mediaSource);
172    if (source == NULL) {
173        return ERROR_UNSUPPORTED;
174    }
175    Mutex::Autolock autoLock(mLock);
176    mTextInBandVector.add(source);
177    if (mState == UNINITIALIZED) {
178        mState = STOPPED;
179    }
180    return OK;
181}
182
183status_t TimedTextDriver::addOutOfBandTextSource(
184        const Parcel &request) {
185    // TODO: Define "TimedTextSource::CreateFromURI(uri)"
186    // and move below lines there..?
187
188    // String values written in Parcel are UTF-16 values.
189    const String16 uri16 = request.readString16();
190    String8 uri = String8(request.readString16());
191
192    uri.toLower();
193    // To support local subtitle file only for now
194    if (strncasecmp("file://", uri.string(), 7)) {
195        return ERROR_UNSUPPORTED;
196    }
197    sp<DataSource> dataSource =
198            DataSource::CreateFromURI(uri);
199    if (dataSource == NULL) {
200        return ERROR_UNSUPPORTED;
201    }
202
203    sp<TimedTextSource> source;
204    if (uri.getPathExtension() == String8(".srt")) {
205        source = TimedTextSource::CreateTimedTextSource(
206                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
207    }
208
209    if (source == NULL) {
210        return ERROR_UNSUPPORTED;
211    }
212
213    Mutex::Autolock autoLock(mLock);
214
215    mTextOutOfBandVector.add(source);
216    if (mState == UNINITIALIZED) {
217        mState = STOPPED;
218    }
219    return OK;
220}
221
222}  // namespace android
223