From 3b573f7bf1c5736d500e39013b8d32478a1429e6 Mon Sep 17 00:00:00 2001 From: Gloria Wang Date: Tue, 31 May 2011 16:08:47 -0700 Subject: Timed text display format support: 1. Extract 3GPP global format descriptions 2. Extract 3GPP local format descriptions 3. Define data structure (TimedText) for applications to retrieve the format metadata Change-Id: I6eac2a78df29ee15beee456656331fdd83b24e8e --- media/libstagefright/timedtext/TimedTextPlayer.cpp | 147 +++++++++++++++------ 1 file changed, 108 insertions(+), 39 deletions(-) (limited to 'media/libstagefright/timedtext/TimedTextPlayer.cpp') diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp index 50bb16d..7c8a747 100644 --- a/media/libstagefright/timedtext/TimedTextPlayer.cpp +++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp @@ -19,6 +19,7 @@ #include #include + #include #include #include @@ -27,9 +28,11 @@ #include #include #include + #include "include/AwesomePlayer.h" #include "TimedTextPlayer.h" #include "TimedTextParser.h" +#include "TextDescriptions.h" namespace android { @@ -92,10 +95,11 @@ status_t TimedTextPlayer::start(uint8_t index) { return BAD_VALUE; } + status_t err; if (index < mTextTrackVector.size()) { // start an in-band text mSource = mTextTrackVector.itemAt(index); - status_t err = mSource->start(); + err = mSource->start(); if (err != OK) { return err; @@ -112,13 +116,17 @@ status_t TimedTextPlayer::start(uint8_t index) { mTextParser = new TimedTextParser(); } - status_t err; if ((err = mTextParser->init(mOutOfBandSource, fileType)) != OK) { return err; } mTextType = kOutOfBandText; } + // send sample description format + if ((err = extractAndSendGlobalDescriptions()) != OK) { + return err; + } + int64_t positionUs; mObserver->getPosition(&positionUs); seekTo(positionUs); @@ -211,21 +219,17 @@ void TimedTextPlayer::onTextEvent() { } mTextEventPending = false; + if (mData.dataSize() > 0) { + notifyListener(MEDIA_TIMED_TEXT, &mData); + mData.freeData(); + } + MediaSource::ReadOptions options; if (mSeeking) { options.setSeekTo(mSeekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); mSeeking = false; - if (mTextType == kInBandText) { - if (mTextBuffer != NULL) { - mTextBuffer->release(); - mTextBuffer = NULL; - } - } else { - mText.clear(); - } - notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen } @@ -233,32 +237,12 @@ void TimedTextPlayer::onTextEvent() { mObserver->getPosition(&positionUs); if (mTextType == kInBandText) { - 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; } mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs); } else { - if (mText.size() > 0) { - notifyListener(MEDIA_TIMED_TEXT, - mText.c_str(), - mText.size()); - mText.clear(); - } - int64_t endTimeUs; if (mTextParser->getText( &mText, &timeUs, &endTimeUs, &options) != OK) { @@ -266,6 +250,19 @@ void TimedTextPlayer::onTextEvent() { } } + if (timeUs > 0) { + extractAndAppendLocalDescriptions(timeUs); + } + + if (mTextType == kInBandText) { + if (mTextBuffer != NULL) { + mTextBuffer->release(); + mTextBuffer = NULL; + } + } else { + mText.clear(); + } + //send the text now if (timeUs <= positionUs + 100000ll) { postTextEvent(); @@ -297,7 +294,8 @@ status_t TimedTextPlayer::setParameter(int key, const Parcel &request) { Mutex::Autolock autoLock(mLock); if (key == KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE) { - String8 uri = request.readString8(); + const String16 uri16 = request.readString16(); + String8 uri = String8(uri16); KeyedVector headers; // To support local subtitle file only for now @@ -327,21 +325,92 @@ status_t TimedTextPlayer::setParameter(int key, const Parcel &request) { return INVALID_OPERATION; } -void TimedTextPlayer::notifyListener( - int msg, const void *data, size_t size) { +void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) { if (mListener != NULL) { sp listener = mListener.promote(); if (listener != NULL) { - if (size > 0) { - mData.freeData(); - mData.write(data, size); - - listener->sendEvent(msg, 0, 0, &mData); + if (parcel && (parcel->dataSize() > 0)) { + listener->sendEvent(msg, 0, 0, parcel); } else { // send an empty timed text to clear the screen listener->sendEvent(msg); } } } } + +// Each text sample consists of a string of text, optionally with sample +// modifier description. The modifier description could specify a new +// text style for the string of text. These descriptions are present only +// if they are needed. This method is used to extract the modifier +// description and append it at the end of the text. +status_t TimedTextPlayer::extractAndAppendLocalDescriptions(int64_t timeUs) { + const void *data; + size_t size = 0; + int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS; + + if (mTextType == kInBandText) { + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { + flag |= TextDescriptions::IN_BAND_TEXT_3GPP; + data = mTextBuffer->data(); + size = mTextBuffer->size(); + } else { + // support 3GPP only for now + return ERROR_UNSUPPORTED; + } + } else { + data = mText.c_str(); + size = mText.size(); + flag |= TextDescriptions::OUT_OF_BAND_TEXT_SRT; + } + + if ((size > 0) && (flag != TextDescriptions::LOCAL_DESCRIPTIONS)) { + mData.freeData(); + return TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, timeUs / 1000, &mData); + } + + return OK; +} + +// To extract and send the global text descriptions for all the text samples +// in the text track or text file. +status_t TimedTextPlayer::extractAndSendGlobalDescriptions() { + const void *data; + size_t size = 0; + int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS; + + if (mTextType == kInBandText) { + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + // support 3GPP only for now + if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { + uint32_t type; + // get the 'tx3g' box content. This box contains the text descriptions + // used to render the text track + if (!mSource->getFormat()->findData( + kKeyTextFormatData, &type, &data, &size)) { + return ERROR_MALFORMED; + } + + flag |= TextDescriptions::IN_BAND_TEXT_3GPP; + } + } + + if ((size > 0) && (flag != TextDescriptions::GLOBAL_DESCRIPTIONS)) { + Parcel parcel; + if (TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, 0, &parcel) == OK) { + if (parcel.dataSize() > 0) { + notifyListener(MEDIA_TIMED_TEXT, &parcel); + } + } + } + + return OK; +} } -- cgit v1.1