summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGloria Wang <gwang@google.com>2011-05-03 15:59:03 -0700
committerGloria Wang <gwang@google.com>2011-05-03 16:41:17 -0700
commit7a1e3e81264189e23a1db2b174e1b5a5d4c7d1c3 (patch)
treed75e0a639df8f389786d9bdf6c6de1f22729b135
parent10d227074b5a67a2e738d72888ece4dd24537c66 (diff)
downloadframeworks_av-7a1e3e81264189e23a1db2b174e1b5a5d4c7d1c3.zip
frameworks_av-7a1e3e81264189e23a1db2b174e1b5a5d4c7d1c3.tar.gz
frameworks_av-7a1e3e81264189e23a1db2b174e1b5a5d4c7d1c3.tar.bz2
Initial CL for the timed text support:
- Add support for MP4 timed text - Add API for app to turn on/off a text track - Add timed text metadata(language) in the MediaMetadataRetriever Change-Id: I0055beba38ac761627dbcc6d581ae9582d68bb94
-rw-r--r--include/media/mediametadataretriever.h1
-rw-r--r--include/media/mediaplayer.h3
-rw-r--r--include/media/stagefright/MediaDefs.h2
-rw-r--r--include/media/stagefright/MetaData.h3
-rw-r--r--media/libstagefright/Android.mk1
-rw-r--r--media/libstagefright/AwesomePlayer.cpp70
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp38
-rw-r--r--media/libstagefright/MediaDefs.cpp2
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp14
-rw-r--r--media/libstagefright/TimedTextPlayer.cpp252
-rw-r--r--media/libstagefright/include/AwesomePlayer.h42
-rw-r--r--media/libstagefright/include/TimedTextPlayer.h91
12 files changed, 496 insertions, 23 deletions
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 3e343e0..28f305d 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -52,6 +52,7 @@ enum {
METADATA_KEY_VIDEO_WIDTH = 18,
METADATA_KEY_VIDEO_HEIGHT = 19,
METADATA_KEY_BITRATE = 20,
+ METADATA_KEY_TIMED_TEXT_LANGUAGES = 21,
// Add more here...
};
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 241626c..cfa4cfd 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -125,6 +125,9 @@ enum media_player_states {
MEDIA_PLAYER_PLAYBACK_COMPLETE = 1 << 7
};
+enum media_set_parameter_keys {
+ KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000,
+};
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class MediaPlayerListener: virtual public RefBase
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 6a21627..5e471c1 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -49,6 +49,8 @@ extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
+extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
+
} // namespace android
#endif // MEDIA_DEFS_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index f7f2235..4044c5d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -114,6 +114,9 @@ enum {
// An indication that a video buffer has been rendered.
kKeyRendered = 'rend', // bool (int32_t)
+
+ // The language code for this media
+ kKeyMediaLanguage = 'lang', // cstring
};
enum {
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2f3e141..6c7176c 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -48,6 +48,7 @@ LOCAL_SRC_FILES:= \
ThrottledSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
+ TimedTextPlayer.cpp \
Utils.cpp \
VBRISeeker.cpp \
WAVExtractor.cpp \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 974efa7..cccd0b7 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -28,6 +28,7 @@
#include "include/NuCachedSource2.h"
#include "include/ThrottledSource.h"
#include "include/MPEG2TSExtractor.h"
+#include "include/TimedTextPlayer.h"
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -185,7 +186,8 @@ AwesomePlayer::AwesomePlayer()
mExtractorFlags(0),
mVideoBuffer(NULL),
mDecryptHandle(NULL),
- mLastVideoTimeUs(-1) {
+ mLastVideoTimeUs(-1),
+ mTextPlayer(NULL) {
CHECK_EQ(mClient.connect(), (status_t)OK);
DataSource::RegisterDefaultSniffers();
@@ -381,10 +383,8 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
mFlags |= AUTO_LOOPING;
}
}
- }
-
- if (haveAudio && haveVideo) {
- break;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ addTextSource(extractor->getTrack(i));
}
}
@@ -469,6 +469,11 @@ void AwesomePlayer::reset_l() {
delete mAudioPlayer;
mAudioPlayer = NULL;
+ if (mTextPlayer != NULL) {
+ delete mTextPlayer;
+ mTextPlayer = NULL;
+ }
+
mVideoRenderer.clear();
if (mRTSPController != NULL) {
@@ -971,6 +976,11 @@ status_t AwesomePlayer::pause_l(bool at_eos) {
mFlags &= ~AUDIO_RUNNING;
}
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mTextPlayer->pause();
+ mFlags &= ~TEXT_RUNNING;
+ }
+
mFlags &= ~PLAYING;
if (mDecryptHandle != NULL) {
@@ -1119,6 +1129,32 @@ status_t AwesomePlayer::seekTo(int64_t timeUs) {
return OK;
}
+status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
+ if (mTextPlayer != NULL) {
+ if (index >= 0) { // to turn on a text track
+ status_t err = mTextPlayer->setTimedTextTrackIndex(index);
+ if (err != OK) {
+ return err;
+ }
+
+ mFlags |= TEXT_RUNNING;
+ mFlags |= TEXTPLAYER_STARTED;
+ return OK;
+ } else { // to turn off the text track display
+ if (mFlags & TEXT_RUNNING) {
+ mFlags &= ~TEXT_RUNNING;
+ }
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mFlags &= ~TEXTPLAYER_STARTED;
+ }
+
+ return mTextPlayer->setTimedTextTrackIndex(index);
+ }
+ } else {
+ return INVALID_OPERATION;
+ }
+}
+
// static
void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
@@ -1155,6 +1191,10 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
seekAudioIfNecessary_l();
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mTextPlayer->seekTo(mSeekTimeUs);
+ }
+
if (!(mFlags & PLAYING)) {
LOGV("seeking while paused, sending SEEK_COMPLETE notification"
" immediately.");
@@ -1193,6 +1233,16 @@ void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
mAudioTrack = source;
}
+void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+ CHECK(source != NULL);
+
+ if (mTextPlayer == NULL) {
+ mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+ }
+
+ mTextPlayer->addTextSource(source);
+}
+
status_t AwesomePlayer::initAudioDecoder() {
sp<MetaData> meta = mAudioTrack->getFormat();
@@ -1472,6 +1522,11 @@ void AwesomePlayer::onVideoEvent() {
}
}
+ if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
+ mTextPlayer->resume();
+ mFlags |= TEXT_RUNNING;
+ }
+
TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
if (mFlags & FIRST_FRAME) {
@@ -1906,7 +1961,10 @@ void AwesomePlayer::postAudioSeekComplete() {
}
status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
- return OK;
+ if (key == KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX) {
+ return setTimedTextTrackIndex(request.readInt32());
+ }
+ return ERROR_UNSUPPORTED;
}
status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 8787214..c79d02e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -19,6 +19,8 @@
#include "include/MPEG4Extractor.h"
#include "include/SampleTable.h"
+#include "include/ESDS.h"
+#include "include/TimedTextPlayer.h"
#include <arpa/inet.h>
@@ -29,7 +31,6 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include "include/ESDS.h"
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -832,6 +833,33 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
mLastTrack->meta->setInt64(
kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
+ uint8_t lang[2];
+ off64_t lang_offset;
+ if (version == 1) {
+ lang_offset = timescale_offset + 4 + 8;
+ } else if (version == 0) {
+ lang_offset = timescale_offset + 4 + 4;
+ } else {
+ return ERROR_IO;
+ }
+
+ if (mDataSource->readAt(lang_offset, &lang, sizeof(lang))
+ < (ssize_t)sizeof(lang)) {
+ return ERROR_IO;
+ }
+
+ // To get the ISO-639-2/T three character language code
+ // 1 bit pad followed by 3 5-bits characters. Each character
+ // is packed as the difference between its ASCII value and 0x60.
+ char lang_code[4];
+ lang_code[0] = ((lang[0] >> 2) & 0x1f) + 0x60;
+ lang_code[1] = ((lang[0] & 0x3) << 3 | (lang[1] >> 5)) + 0x60;
+ lang_code[2] = (lang[1] & 0x1f) + 0x60;
+ lang_code[3] = '\0';
+
+ mLastTrack->meta->setCString(
+ kKeyMediaLanguage, lang_code);
+
*offset += chunk_size;
break;
}
@@ -1295,6 +1323,14 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return parseDrmSINF(offset, data_offset);
}
+ case FOURCC('t', 'x', '3', 'g'):
+ {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+
+ *offset += chunk_size;
+ break;
+ }
+
default:
{
*offset += chunk_size;
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 8ca6ee8..8cd08bc 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -47,4 +47,6 @@ const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
+const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
+
} // namespace android
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 7621f2c..4c3dc47 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -27,6 +27,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/MediaDefs.h>
namespace android {
@@ -429,6 +430,7 @@ void StagefrightMetadataRetriever::parseMetaData() {
// The overall duration is the duration of the longest track.
int64_t maxDurationUs = 0;
+ String8 timedTextLang;
for (size_t i = 0; i < numTracks; ++i) {
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
@@ -452,10 +454,22 @@ void StagefrightMetadataRetriever::parseMetaData() {
CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ const char *lang;
+ trackMeta->findCString(kKeyMediaLanguage, &lang);
+ timedTextLang.append(String8(lang));
+ timedTextLang.append(String8(":"));
}
}
}
+ // To save the language codes for all timed text tracks
+ // If multiple text tracks present, the format will look
+ // like "eng:chi"
+ if (!timedTextLang.isEmpty()) {
+ mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
+ }
+
// The duration value is a string representing the duration in ms.
sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
diff --git a/media/libstagefright/TimedTextPlayer.cpp b/media/libstagefright/TimedTextPlayer.cpp
new file mode 100644
index 0000000..1ac22cb
--- /dev/null
+++ b/media/libstagefright/TimedTextPlayer.cpp
@@ -0,0 +1,252 @@
+ /*
+ * Copyright (C) 2011 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 "TimedTextPlayer"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/Utils.h>
+#include "include/AwesomePlayer.h"
+#include "include/TimedTextPlayer.h"
+
+namespace android {
+
+struct TimedTextEvent : public TimedEventQueue::Event {
+ TimedTextEvent(
+ TimedTextPlayer *player,
+ void (TimedTextPlayer::*method)())
+ : mPlayer(player),
+ mMethod(method) {
+ }
+
+protected:
+ virtual ~TimedTextEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ (mPlayer->*mMethod)();
+ }
+
+private:
+ TimedTextPlayer *mPlayer;
+ void (TimedTextPlayer::*mMethod)();
+
+ TimedTextEvent(const TimedTextEvent &);
+ TimedTextEvent &operator=(const TimedTextEvent &);
+};
+
+TimedTextPlayer::TimedTextPlayer(
+ AwesomePlayer *observer,
+ const wp<MediaPlayerBase> &listener,
+ TimedEventQueue *queue)
+ : mSource(NULL),
+ mSeekTimeUs(0),
+ mStarted(false),
+ mTextEventPending(false),
+ mQueue(queue),
+ mListener(listener),
+ mObserver(observer),
+ mTextBuffer(NULL) {
+ mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent);
+}
+
+TimedTextPlayer::~TimedTextPlayer() {
+ if (mStarted) {
+ reset();
+ }
+
+ mTextTrackVector.clear();
+}
+
+status_t TimedTextPlayer::start(uint8_t index) {
+ CHECK(!mStarted);
+
+ if (index >= mTextTrackVector.size()) {
+ LOGE("Incorrect text track index");
+ return BAD_VALUE;
+ }
+
+ mSource = mTextTrackVector.itemAt(index);
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ int64_t positionUs;
+ mObserver->getPosition(&positionUs);
+ seekTo(positionUs);
+
+ postTextEvent();
+
+ mStarted = true;
+
+ return OK;
+}
+
+void TimedTextPlayer::pause() {
+ CHECK(mStarted);
+
+ cancelTextEvent();
+}
+
+void TimedTextPlayer::resume() {
+ CHECK(mStarted);
+
+ postTextEvent();
+}
+
+void TimedTextPlayer::reset() {
+ CHECK(mStarted);
+
+ // send an empty text to clear the screen
+ notifyListener(MEDIA_TIMED_TEXT);
+
+ cancelTextEvent();
+
+ mSeeking = false;
+ mStarted = false;
+
+ if (mTextBuffer != NULL) {
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+ }
+
+ if (mSource != NULL) {
+ mSource->stop();
+ mSource.clear();
+ mSource = NULL;
+ }
+}
+
+status_t TimedTextPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+
+ return OK;
+}
+
+status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) {
+ if (index >= (int)(mTextTrackVector.size())) {
+ return BAD_VALUE;
+ }
+
+ if (mStarted) {
+ reset();
+ }
+
+ if (index >= 0) {
+ return start(index);
+ }
+ return OK;
+}
+
+void TimedTextPlayer::onTextEvent() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (!mTextEventPending) {
+ return;
+ }
+ mTextEventPending = false;
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ mSeeking = false;
+
+ if (mTextBuffer != NULL) {
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+ }
+
+ notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
+ }
+
+ if (mTextBuffer != NULL) {
+ uint8_t *tmp = (uint8_t *)(mTextBuffer->data());
+ size_t len = (*tmp) << 8 | (*(tmp + 1));
+
+ notifyListener(MEDIA_TIMED_TEXT,
+ tmp + 2,
+ len);
+
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+
+ }
+
+ if (mSource->read(&mTextBuffer, &options) != OK) {
+ return;
+ }
+
+ int64_t positionUs, timeUs;
+ mObserver->getPosition(&positionUs);
+ mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
+
+ //send the text now
+ if (timeUs <= positionUs + 100000ll) {
+ postTextEvent();
+ } else {
+ postTextEvent(timeUs - positionUs - 100000ll);
+ }
+}
+
+void TimedTextPlayer::postTextEvent(int64_t delayUs) {
+ if (mTextEventPending) {
+ return;
+ }
+
+ mTextEventPending = true;
+ mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void TimedTextPlayer::cancelTextEvent() {
+ mQueue->cancelEvent(mTextEvent->eventID());
+ mTextEventPending = false;
+}
+
+void TimedTextPlayer::addTextSource(sp<MediaSource> source) {
+ mTextTrackVector.add(source);
+}
+
+void TimedTextPlayer::notifyListener(
+ int msg, const void *data, size_t size) {
+ if (mListener != NULL) {
+ sp<MediaPlayerBase> listener = mListener.promote();
+
+ if (listener != NULL) {
+ if (size > 0) {
+ mData.freeData();
+ mData.write(data, size);
+
+ listener->sendEvent(msg, 0, 0, &mData);
+ } else { // send an empty timed text to clear the screen
+ listener->sendEvent(msg);
+ }
+ }
+ }
+}
+}
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 2c17d92..fd3ddf7 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -44,6 +44,8 @@ struct ARTSPController;
class DrmManagerClinet;
class DecryptHandle;
+class TimedTextPlayer;
+
struct AwesomeRenderer : public RefBase {
AwesomeRenderer() {}
@@ -99,36 +101,41 @@ struct AwesomePlayer {
void postAudioEOS(int64_t delayUs = 0ll);
void postAudioSeekComplete();
+ status_t setTimedTextTrackIndex(int32_t index);
+
private:
friend struct AwesomeEvent;
friend struct PreviewPlayer;
enum {
- PLAYING = 1,
- LOOPING = 2,
- FIRST_FRAME = 4,
- PREPARING = 8,
- PREPARED = 16,
- AT_EOS = 32,
- PREPARE_CANCELLED = 64,
- CACHE_UNDERRUN = 128,
- AUDIO_AT_EOS = 256,
- VIDEO_AT_EOS = 512,
- AUTO_LOOPING = 1024,
+ PLAYING = 0x01,
+ LOOPING = 0x02,
+ FIRST_FRAME = 0x04,
+ PREPARING = 0x08,
+ PREPARED = 0x10,
+ AT_EOS = 0x20,
+ PREPARE_CANCELLED = 0x40,
+ CACHE_UNDERRUN = 0x80,
+ AUDIO_AT_EOS = 0x0100,
+ VIDEO_AT_EOS = 0x0200,
+ AUTO_LOOPING = 0x0400,
// We are basically done preparing but are currently buffering
// sufficient data to begin playback and finish the preparation phase
// for good.
- PREPARING_CONNECTED = 2048,
+ PREPARING_CONNECTED = 0x0800,
// We're triggering a single video event to display the first frame
// after the seekpoint.
- SEEK_PREVIEW = 4096,
+ SEEK_PREVIEW = 0x1000,
- AUDIO_RUNNING = 8192,
- AUDIOPLAYER_STARTED = 16384,
+ AUDIO_RUNNING = 0x2000,
+ AUDIOPLAYER_STARTED = 0x4000,
- INCOGNITO = 32768,
+ INCOGNITO = 0x8000,
+
+ TEXT_RUNNING = 0x10000,
+ TEXTPLAYER_STARTED = 0x20000,
};
mutable Mutex mLock;
@@ -222,6 +229,7 @@ private:
sp<DecryptHandle> mDecryptHandle;
int64_t mLastVideoTimeUs;
+ TimedTextPlayer *mTextPlayer;
status_t setDataSource_l(
const char *uri,
@@ -244,6 +252,8 @@ private:
void setVideoSource(sp<MediaSource> source);
status_t initVideoDecoder(uint32_t flags = 0);
+ void addTextSource(sp<MediaSource> source);
+
void onStreamDone();
void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
diff --git a/media/libstagefright/include/TimedTextPlayer.h b/media/libstagefright/include/TimedTextPlayer.h
new file mode 100644
index 0000000..ac41b4f
--- /dev/null
+++ b/media/libstagefright/include/TimedTextPlayer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef TIMEDTEXT_PLAYER_H_
+
+#define TIMEDTEXT_PLAYER_H_
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#include "include/TimedEventQueue.h"
+
+namespace android {
+
+class MediaSource;
+class AwesomePlayer;
+class MediaBuffer;
+
+class TimedTextPlayer {
+public:
+ TimedTextPlayer(AwesomePlayer *observer,
+ const wp<MediaPlayerBase> &listener,
+ TimedEventQueue *queue);
+
+ virtual ~TimedTextPlayer();
+
+ // index: the index of the text track which will
+ // be turned on
+ status_t start(uint8_t index);
+
+ void pause();
+
+ void resume();
+
+ status_t seekTo(int64_t time_us);
+
+ void addTextSource(sp<MediaSource> source);
+
+ status_t setTimedTextTrackIndex(int32_t index);
+
+private:
+ Mutex mLock;
+
+ sp<MediaSource> mSource;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+
+ sp<TimedEventQueue::Event> mTextEvent;
+ bool mTextEventPending;
+
+ TimedEventQueue *mQueue;
+
+ wp<MediaPlayerBase> mListener;
+ AwesomePlayer *mObserver;
+
+ MediaBuffer *mTextBuffer;
+ Parcel mData;
+
+ Vector<sp<MediaSource> > mTextTrackVector;
+
+ void reset();
+
+ void onTextEvent();
+ void postTextEvent(int64_t delayUs = -1);
+ void cancelTextEvent();
+
+ void notifyListener(
+ int msg, const void *data = NULL, size_t size = 0);
+
+ DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
+};
+
+} // namespace android
+
+#endif // TIMEDTEXT_PLAYER_H_