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