TimedTextDriver.cpp revision 692ac36c4b6a09fed5113a4f45f00a041665a769
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            break;
80        default:
81            TRESPASS();
82    }
83    mState = PLAYING;
84    return OK;
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            break;
99        case PAUSED:
100            return OK;
101        default:
102            TRESPASS();
103    }
104    mState = PAUSED;
105    return OK;
106}
107
108status_t TimedTextDriver::selectTrack(size_t index) {
109    status_t ret = OK;
110    Mutex::Autolock autoLock(mLock);
111    switch (mState) {
112        case UNINITIALIZED:
113        case PAUSED:
114            ret = selectTrack_l(index);
115            break;
116        case PLAYING:
117            mPlayer->pause();
118            ret = selectTrack_l(index);
119            if (ret != OK) {
120                break;
121            }
122            mPlayer->start();
123            break;
124        defaut:
125            TRESPASS();
126    }
127    return ret;
128}
129
130status_t TimedTextDriver::unselectTrack(size_t index) {
131    if (mCurrentTrackIndex != index) {
132        return INVALID_OPERATION;
133    }
134    status_t err = pause();
135    if (err != OK) {
136        return err;
137    }
138    Mutex::Autolock autoLock(mLock);
139    mState = UNINITIALIZED;
140    return OK;
141}
142
143status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
144    mPlayer->seekToAsync(timeUs);
145    return OK;
146}
147
148status_t TimedTextDriver::addInBandTextSource(
149        size_t trackIndex, const sp<MediaSource>& mediaSource) {
150    sp<TimedTextSource> source =
151            TimedTextSource::CreateTimedTextSource(mediaSource);
152    if (source == NULL) {
153        return ERROR_UNSUPPORTED;
154    }
155    Mutex::Autolock autoLock(mLock);
156    mTextSourceVector.add(trackIndex, source);
157    mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_IN_BAND);
158    return OK;
159}
160
161status_t TimedTextDriver::addOutOfBandTextSource(
162        size_t trackIndex, const char *uri, const char *mimeType) {
163
164    // To support local subtitle file only for now
165    if (strncasecmp("file://", uri, 7)) {
166        ALOGE("uri('%s') is not a file", uri);
167        return ERROR_UNSUPPORTED;
168    }
169
170    sp<DataSource> dataSource =
171            DataSource::CreateFromURI(uri);
172    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
173}
174
175status_t TimedTextDriver::addOutOfBandTextSource(
176        size_t trackIndex, int fd, off64_t offset, off64_t length, const char *mimeType) {
177
178    if (fd < 0) {
179        ALOGE("Invalid file descriptor: %d", fd);
180        return ERROR_UNSUPPORTED;
181    }
182
183    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
184    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
185}
186
187status_t TimedTextDriver::createOutOfBandTextSource(
188        size_t trackIndex,
189        const char *mimeType,
190        const sp<DataSource>& dataSource) {
191
192    if (dataSource == NULL) {
193        return ERROR_UNSUPPORTED;
194    }
195
196    sp<TimedTextSource> source;
197    if (strcasecmp(mimeType, MEDIA_MIMETYPE_TEXT_SUBRIP) == 0) {
198        source = TimedTextSource::CreateTimedTextSource(
199                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
200    }
201
202    if (source == NULL) {
203        ALOGE("Failed to create timed text source");
204        return ERROR_UNSUPPORTED;
205    }
206
207    Mutex::Autolock autoLock(mLock);
208    mTextSourceVector.add(trackIndex, source);
209    mTextSourceTypeVector.add(TEXT_SOURCE_TYPE_OUT_OF_BAND);
210    return OK;
211}
212
213size_t TimedTextDriver::countExternalTracks() const {
214    size_t nTracks = 0;
215    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
216        if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_OUT_OF_BAND) {
217            ++nTracks;
218        }
219    }
220    return nTracks;
221}
222
223void TimedTextDriver::getExternalTrackInfo(Parcel *parcel) {
224    Mutex::Autolock autoLock(mLock);
225    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
226        if (mTextSourceTypeVector[i] == TEXT_SOURCE_TYPE_IN_BAND) {
227            continue;
228        }
229
230        sp<MetaData> meta = mTextSourceVector.valueAt(i)->getFormat();
231
232        // There are two fields.
233        parcel->writeInt32(2);
234
235        // track type.
236        parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
237        const char *lang = "und";
238        if (meta != NULL) {
239            meta->findCString(kKeyMediaLanguage, &lang);
240        }
241        parcel->writeString16(String16(lang));
242    }
243}
244
245}  // namespace android
246