TimedTextDriver.cpp revision 7c5afe93c9ca2f9f3958663bc3fa9649ec2f5331
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/MediaDefs.h>
27#include <media/stagefright/MediaErrors.h>
28#include <media/stagefright/MediaSource.h>
29#include <media/stagefright/MetaData.h>
30#include <media/stagefright/Utils.h>
31#include <media/stagefright/foundation/ADebug.h>
32#include <media/stagefright/foundation/ALooper.h>
33#include <media/stagefright/timedtext/TimedTextDriver.h>
34
35#include "TextDescriptions.h"
36#include "TimedTextPlayer.h"
37#include "TimedTextSource.h"
38
39namespace android {
40
41TimedTextDriver::TimedTextDriver(
42        const wp<MediaPlayerBase> &listener)
43    : mLooper(new ALooper),
44      mListener(listener),
45      mState(UNINITIALIZED) {
46    mLooper->setName("TimedTextDriver");
47    mLooper->start();
48    mPlayer = new TimedTextPlayer(listener);
49    mLooper->registerHandler(mPlayer);
50}
51
52TimedTextDriver::~TimedTextDriver() {
53    mTextSourceVector.clear();
54    mLooper->stop();
55}
56
57status_t TimedTextDriver::selectTrack_l(int32_t index) {
58    if (index >= (int)(mTextSourceVector.size())) {
59        return BAD_VALUE;
60    }
61
62    sp<TimedTextSource> source;
63    source = mTextSourceVector.itemAt(index);
64    mPlayer->setDataSource(source);
65    if (mState == UNINITIALIZED) {
66        mState = PAUSED;
67    }
68    mCurrentTrackIndex = index;
69    return OK;
70}
71
72status_t TimedTextDriver::start() {
73    Mutex::Autolock autoLock(mLock);
74    switch (mState) {
75        case UNINITIALIZED:
76            return INVALID_OPERATION;
77        case PLAYING:
78            return OK;
79        case PAUSED:
80            mPlayer->start();
81            break;
82        default:
83            TRESPASS();
84    }
85    mState = PLAYING;
86    return OK;
87}
88
89// TODO: Test if pause() works properly.
90// Scenario 1: start - pause - resume
91// Scenario 2: start - seek
92// Scenario 3: start - pause - seek - resume
93status_t TimedTextDriver::pause() {
94    Mutex::Autolock autoLock(mLock);
95    switch (mState) {
96        case UNINITIALIZED:
97            return INVALID_OPERATION;
98        case PLAYING:
99            mPlayer->pause();
100            break;
101        case PAUSED:
102            return OK;
103        default:
104            TRESPASS();
105    }
106    mState = PAUSED;
107    return OK;
108}
109
110status_t TimedTextDriver::selectTrack(int32_t index) {
111    status_t ret = OK;
112    Mutex::Autolock autoLock(mLock);
113    switch (mState) {
114        case UNINITIALIZED:
115        case PAUSED:
116            ret = selectTrack_l(index);
117            break;
118        case PLAYING:
119            mPlayer->pause();
120            ret = selectTrack_l(index);
121            if (ret != OK) {
122                break;
123            }
124            mPlayer->start();
125            break;
126        defaut:
127            TRESPASS();
128    }
129    return ret;
130}
131
132status_t TimedTextDriver::unselectTrack(int32_t index) {
133    if (mCurrentTrackIndex != index) {
134        return INVALID_OPERATION;
135    }
136    status_t err = pause();
137    if (err != OK) {
138        return err;
139    }
140    Mutex::Autolock autoLock(mLock);
141    mState = UNINITIALIZED;
142    return OK;
143}
144
145status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
146    mPlayer->seekToAsync(timeUs);
147    return OK;
148}
149
150status_t TimedTextDriver::addInBandTextSource(
151        const sp<MediaSource>& mediaSource) {
152    sp<TimedTextSource> source =
153            TimedTextSource::CreateTimedTextSource(mediaSource);
154    if (source == NULL) {
155        return ERROR_UNSUPPORTED;
156    }
157    Mutex::Autolock autoLock(mLock);
158    mTextSourceVector.add(source);
159    return OK;
160}
161
162status_t TimedTextDriver::addOutOfBandTextSource(
163        const char *uri, const char *mimeType) {
164    // TODO: Define "TimedTextSource::CreateFromURI(uri)"
165    // and move below lines there..?
166
167    // To support local subtitle file only for now
168    if (strncasecmp("file://", uri, 7)) {
169        return ERROR_UNSUPPORTED;
170    }
171    sp<DataSource> dataSource =
172            DataSource::CreateFromURI(uri);
173    if (dataSource == NULL) {
174        return ERROR_UNSUPPORTED;
175    }
176
177    sp<TimedTextSource> source;
178    if (strcasecmp(mimeType, MEDIA_MIMETYPE_TEXT_SUBRIP) == 0) {
179        source = TimedTextSource::CreateTimedTextSource(
180                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
181    }
182
183    if (source == NULL) {
184        return ERROR_UNSUPPORTED;
185    }
186
187    Mutex::Autolock autoLock(mLock);
188    mTextSourceVector.add(source);
189    return OK;
190}
191
192status_t TimedTextDriver::addOutOfBandTextSource(
193        int fd, off64_t offset, size_t length, const char *mimeType) {
194    // Not supported yet. This requires DataSource::sniff to detect various text
195    // formats such as srt/smi/ttml.
196    return ERROR_UNSUPPORTED;
197}
198
199void TimedTextDriver::getTrackInfo(Parcel *parcel) {
200    Mutex::Autolock autoLock(mLock);
201    Vector<sp<TimedTextSource> >::const_iterator iter;
202    parcel->writeInt32(mTextSourceVector.size());
203    for (iter = mTextSourceVector.begin();
204         iter != mTextSourceVector.end(); ++iter) {
205        sp<MetaData> meta = (*iter)->getFormat();
206        if (meta != NULL) {
207            // There are two fields.
208            parcel->writeInt32(2);
209
210            // track type.
211            parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
212
213            const char *lang = "und";
214            meta->findCString(kKeyMediaLanguage, &lang);
215            parcel->writeString16(String16(lang));
216        } else {
217            parcel->writeInt32(0);
218        }
219    }
220}
221
222}  // namespace android
223