TimedTextDriver.cpp revision 25736fd247ba757feefe15d3071f7e747c64fea4
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    mLooper->stop();
56}
57
58status_t TimedTextDriver::selectTrack_l(int32_t index) {
59    if (index >= (int)(mTextSourceVector.size())) {
60        return BAD_VALUE;
61    }
62
63    sp<TimedTextSource> source;
64    source = mTextSourceVector.itemAt(index);
65    mPlayer->setDataSource(source);
66    if (mState == UNINITIALIZED) {
67        mState = PAUSED;
68    }
69    mCurrentTrackIndex = index;
70    return OK;
71}
72
73status_t TimedTextDriver::start() {
74    Mutex::Autolock autoLock(mLock);
75    switch (mState) {
76        case UNINITIALIZED:
77            return INVALID_OPERATION;
78        case PLAYING:
79            return OK;
80        case PAUSED:
81            mPlayer->start();
82            break;
83        default:
84            TRESPASS();
85    }
86    mState = PLAYING;
87    return OK;
88}
89
90// TODO: Test if pause() works properly.
91// Scenario 1: start - pause - resume
92// Scenario 2: start - seek
93// Scenario 3: start - pause - seek - resume
94status_t TimedTextDriver::pause() {
95    Mutex::Autolock autoLock(mLock);
96    switch (mState) {
97        case UNINITIALIZED:
98            return INVALID_OPERATION;
99        case PLAYING:
100            mPlayer->pause();
101            break;
102        case PAUSED:
103            return OK;
104        default:
105            TRESPASS();
106    }
107    mState = PAUSED;
108    return OK;
109}
110
111status_t TimedTextDriver::selectTrack(int32_t index) {
112    status_t ret = OK;
113    Mutex::Autolock autoLock(mLock);
114    switch (mState) {
115        case UNINITIALIZED:
116        case PAUSED:
117            ret = selectTrack_l(index);
118            break;
119        case PLAYING:
120            mPlayer->pause();
121            ret = selectTrack_l(index);
122            if (ret != OK) {
123                break;
124            }
125            mPlayer->start();
126            break;
127        defaut:
128            TRESPASS();
129    }
130    return ret;
131}
132
133status_t TimedTextDriver::unselectTrack(int32_t index) {
134    if (mCurrentTrackIndex != index) {
135        return INVALID_OPERATION;
136    }
137    status_t err = pause();
138    if (err != OK) {
139        return err;
140    }
141    Mutex::Autolock autoLock(mLock);
142    mState = UNINITIALIZED;
143    return OK;
144}
145
146status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
147    mPlayer->seekToAsync(timeUs);
148    return OK;
149}
150
151status_t TimedTextDriver::addInBandTextSource(
152        const sp<MediaSource>& mediaSource) {
153    sp<TimedTextSource> source =
154            TimedTextSource::CreateTimedTextSource(mediaSource);
155    if (source == NULL) {
156        return ERROR_UNSUPPORTED;
157    }
158    Mutex::Autolock autoLock(mLock);
159    mTextSourceVector.add(source);
160    return OK;
161}
162
163status_t TimedTextDriver::addOutOfBandTextSource(
164        const char *uri, const char *mimeType) {
165    // To support local subtitle file only for now
166    if (strncasecmp("file://", uri, 7)) {
167        ALOGE("uri('%s') is not a file", uri);
168        return ERROR_UNSUPPORTED;
169    }
170
171    sp<DataSource> dataSource =
172            DataSource::CreateFromURI(uri);
173    return createOutOfBandTextSource(mimeType, dataSource);
174}
175
176status_t TimedTextDriver::addOutOfBandTextSource(
177        int fd, off64_t offset, off64_t length, const char *mimeType) {
178
179    if (fd < 0) {
180        ALOGE("Invalid file descriptor: %d", fd);
181        return ERROR_UNSUPPORTED;
182    }
183
184    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
185    return createOutOfBandTextSource(mimeType, dataSource);
186}
187
188status_t TimedTextDriver::createOutOfBandTextSource(
189        const char *mimeType, const sp<DataSource>& dataSource) {
190
191    if (dataSource == NULL) {
192        return ERROR_UNSUPPORTED;
193    }
194
195    sp<TimedTextSource> source;
196    if (strcasecmp(mimeType, MEDIA_MIMETYPE_TEXT_SUBRIP) == 0) {
197        source = TimedTextSource::CreateTimedTextSource(
198                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
199    }
200
201    if (source == NULL) {
202        return ERROR_UNSUPPORTED;
203    }
204
205    Mutex::Autolock autoLock(mLock);
206    mTextSourceVector.add(source);
207    return OK;
208}
209
210void TimedTextDriver::getTrackInfo(Parcel *parcel) {
211    Mutex::Autolock autoLock(mLock);
212    Vector<sp<TimedTextSource> >::const_iterator iter;
213    parcel->writeInt32(mTextSourceVector.size());
214    for (iter = mTextSourceVector.begin();
215         iter != mTextSourceVector.end(); ++iter) {
216        sp<MetaData> meta = (*iter)->getFormat();
217
218        // There are two fields.
219        parcel->writeInt32(2);
220
221        // track type.
222        parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
223
224        const char *lang = "und";
225        if (meta != NULL) {
226            meta->findCString(kKeyMediaLanguage, &lang);
227        }
228        parcel->writeString16(String16(lang));
229    }
230}
231
232}  // namespace android
233