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/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 
     41 namespace android {
     42 
     43 TimedTextDriver::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 
     57 TimedTextDriver::~TimedTextDriver() {
     58     mTextSourceVector.clear();
     59     mTextSourceTypeVector.clear();
     60     mLooper->stop();
     61 }
     62 
     63 status_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 
     77 status_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 
     98 status_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 
    118 status_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 
    142 status_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 
    166 status_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 
    190 status_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 
    203 status_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 
    217 status_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 
    229 status_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 
    255 size_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 
    265 void 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