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