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     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