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