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