blob: 8ee15f8665ac6efcfd7e2aeea99003a588bca88d [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "TimedTextDriver"
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <media/mediaplayer.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/timedtext/TimedTextDriver.h>
#include "TextDescriptions.h"
#include "TimedTextPlayer.h"
#include "TimedTextSource.h"
namespace android {
TimedTextDriver::TimedTextDriver(
const wp<MediaPlayerBase> &listener)
: mLooper(new ALooper),
mListener(listener),
mState(UNINITIALIZED) {
mLooper->setName("TimedTextDriver");
mLooper->start();
mPlayer = new TimedTextPlayer(listener);
mLooper->registerHandler(mPlayer);
}
TimedTextDriver::~TimedTextDriver() {
mTextSourceVector.clear();
mLooper->stop();
}
status_t TimedTextDriver::selectTrack_l(int32_t index) {
if (index >= (int)(mTextSourceVector.size())) {
return BAD_VALUE;
}
sp<TimedTextSource> source;
source = mTextSourceVector.itemAt(index);
mPlayer->setDataSource(source);
if (mState == UNINITIALIZED) {
mState = PAUSED;
}
mCurrentTrackIndex = index;
return OK;
}
status_t TimedTextDriver::start() {
Mutex::Autolock autoLock(mLock);
switch (mState) {
case UNINITIALIZED:
return INVALID_OPERATION;
case PLAYING:
return OK;
case PAUSED:
mPlayer->start();
break;
default:
TRESPASS();
}
mState = PLAYING;
return OK;
}
// TODO: Test if pause() works properly.
// Scenario 1: start - pause - resume
// Scenario 2: start - seek
// Scenario 3: start - pause - seek - resume
status_t TimedTextDriver::pause() {
Mutex::Autolock autoLock(mLock);
switch (mState) {
case UNINITIALIZED:
return INVALID_OPERATION;
case PLAYING:
mPlayer->pause();
break;
case PAUSED:
return OK;
default:
TRESPASS();
}
mState = PAUSED;
return OK;
}
status_t TimedTextDriver::selectTrack(int32_t index) {
status_t ret = OK;
Mutex::Autolock autoLock(mLock);
switch (mState) {
case UNINITIALIZED:
case PAUSED:
ret = selectTrack_l(index);
break;
case PLAYING:
mPlayer->pause();
ret = selectTrack_l(index);
if (ret != OK) {
break;
}
mPlayer->start();
break;
defaut:
TRESPASS();
}
return ret;
}
status_t TimedTextDriver::unselectTrack(int32_t index) {
if (mCurrentTrackIndex != index) {
return INVALID_OPERATION;
}
status_t err = pause();
if (err != OK) {
return err;
}
Mutex::Autolock autoLock(mLock);
mState = UNINITIALIZED;
return OK;
}
status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
mPlayer->seekToAsync(timeUs);
return OK;
}
status_t TimedTextDriver::addInBandTextSource(
const sp<MediaSource>& mediaSource) {
sp<TimedTextSource> source =
TimedTextSource::CreateTimedTextSource(mediaSource);
if (source == NULL) {
return ERROR_UNSUPPORTED;
}
Mutex::Autolock autoLock(mLock);
mTextSourceVector.add(source);
return OK;
}
status_t TimedTextDriver::addOutOfBandTextSource(
const char *uri, const char *mimeType) {
// TODO: Define "TimedTextSource::CreateFromURI(uri)"
// and move below lines there..?
// To support local subtitle file only for now
if (strncasecmp("file://", uri, 7)) {
return ERROR_UNSUPPORTED;
}
sp<DataSource> dataSource =
DataSource::CreateFromURI(uri);
if (dataSource == NULL) {
return ERROR_UNSUPPORTED;
}
sp<TimedTextSource> source;
if (strcasecmp(mimeType, MEDIA_MIMETYPE_TEXT_SUBRIP) == 0) {
source = TimedTextSource::CreateTimedTextSource(
dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
}
if (source == NULL) {
return ERROR_UNSUPPORTED;
}
Mutex::Autolock autoLock(mLock);
mTextSourceVector.add(source);
return OK;
}
status_t TimedTextDriver::addOutOfBandTextSource(
int fd, off64_t offset, size_t length, const char *mimeType) {
// Not supported yet. This requires DataSource::sniff to detect various text
// formats such as srt/smi/ttml.
return ERROR_UNSUPPORTED;
}
void TimedTextDriver::getTrackInfo(Parcel *parcel) {
Mutex::Autolock autoLock(mLock);
Vector<sp<TimedTextSource> >::const_iterator iter;
parcel->writeInt32(mTextSourceVector.size());
for (iter = mTextSourceVector.begin();
iter != mTextSourceVector.end(); ++iter) {
sp<MetaData> meta = (*iter)->getFormat();
if (meta != NULL) {
// There are two fields.
parcel->writeInt32(2);
// track type.
parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
const char *lang = "und";
meta->findCString(kKeyMediaLanguage, &lang);
parcel->writeString16(String16(lang));
} else {
parcel->writeInt32(0);
}
}
}
} // namespace android