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