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 40 namespace android { 41 42 TimedTextDriver::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 53 TimedTextDriver::~TimedTextDriver() { 54 mTextSourceVector.clear(); 55 mTextSourceTypeVector.clear(); 56 mLooper->stop(); 57 } 58 59 status_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 70 status_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 91 status_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 108 status_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 130 status_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 143 status_t TimedTextDriver::seekToAsync(int64_t timeUs) { 144 mPlayer->seekToAsync(timeUs); 145 return OK; 146 } 147 148 status_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 161 status_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 175 status_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 187 status_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 213 size_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 223 void 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