TimedTextPlayer.cpp revision 3254b25e8b0f674ccc2226609e01dd86a600802e
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 "TimedTextPlayer" 19#include <utils/Log.h> 20 21#include <media/stagefright/foundation/ADebug.h> 22#include <media/stagefright/foundation/AMessage.h> 23#include <media/stagefright/timedtext/TimedTextDriver.h> 24#include <media/stagefright/MediaErrors.h> 25#include <media/MediaPlayerInterface.h> 26 27#include "TimedTextPlayer.h" 28 29#include "TimedTextSource.h" 30 31namespace android { 32 33static const int64_t kAdjustmentProcessingTimeUs = 100000ll; 34 35TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener) 36 : mListener(listener), 37 mSource(NULL), 38 mSendSubtitleGeneration(0) { 39} 40 41TimedTextPlayer::~TimedTextPlayer() { 42 if (mSource != NULL) { 43 mSource->stop(); 44 mSource.clear(); 45 mSource = NULL; 46 } 47} 48 49void TimedTextPlayer::start() { 50 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 51 msg->setInt64("seekTimeUs", -1); 52 msg->post(); 53} 54 55void TimedTextPlayer::pause() { 56 (new AMessage(kWhatPause, id()))->post(); 57} 58 59void TimedTextPlayer::resume() { 60 start(); 61} 62 63void TimedTextPlayer::seekToAsync(int64_t timeUs) { 64 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 65 msg->setInt64("seekTimeUs", timeUs); 66 msg->post(); 67} 68 69void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) { 70 sp<AMessage> msg = new AMessage(kWhatSetSource, id()); 71 msg->setObject("source", source); 72 msg->post(); 73} 74 75void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) { 76 switch (msg->what()) { 77 case kWhatPause: { 78 mSendSubtitleGeneration++; 79 break; 80 } 81 case kWhatSeek: { 82 int64_t seekTimeUs = 0; 83 msg->findInt64("seekTimeUs", &seekTimeUs); 84 if (seekTimeUs < 0) { 85 sp<MediaPlayerBase> listener = mListener.promote(); 86 if (listener != NULL) { 87 int32_t positionMs = 0; 88 listener->getCurrentPosition(&positionMs); 89 seekTimeUs = positionMs * 1000ll; 90 } 91 } 92 doSeekAndRead(seekTimeUs); 93 break; 94 } 95 case kWhatSendSubtitle: { 96 int32_t generation; 97 CHECK(msg->findInt32("generation", &generation)); 98 if (generation != mSendSubtitleGeneration) { 99 // Drop obsolete msg. 100 break; 101 } 102 sp<RefBase> obj; 103 msg->findObject("subtitle", &obj); 104 if (obj != NULL) { 105 sp<ParcelEvent> parcelEvent; 106 parcelEvent = static_cast<ParcelEvent*>(obj.get()); 107 notifyListener(MEDIA_TIMED_TEXT, &(parcelEvent->parcel)); 108 } else { 109 notifyListener(MEDIA_TIMED_TEXT); 110 } 111 doRead(); 112 break; 113 } 114 case kWhatSetSource: { 115 sp<RefBase> obj; 116 msg->findObject("source", &obj); 117 if (obj == NULL) break; 118 if (mSource != NULL) { 119 mSource->stop(); 120 } 121 mSource = static_cast<TimedTextSource*>(obj.get()); 122 mSource->start(); 123 Parcel parcel; 124 if (mSource->extractGlobalDescriptions(&parcel) == OK && 125 parcel.dataSize() > 0) { 126 notifyListener(MEDIA_TIMED_TEXT, &parcel); 127 } else { 128 notifyListener(MEDIA_TIMED_TEXT); 129 } 130 break; 131 } 132 } 133} 134 135void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) { 136 MediaSource::ReadOptions options; 137 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 138 doRead(&options); 139} 140 141void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) { 142 int64_t timeUs = 0; 143 sp<ParcelEvent> parcelEvent = new ParcelEvent(); 144 mSource->read(&timeUs, &(parcelEvent->parcel), options); 145 postTextEvent(parcelEvent, timeUs); 146} 147 148void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) { 149 sp<MediaPlayerBase> listener = mListener.promote(); 150 if (listener != NULL) { 151 int64_t positionUs, delayUs; 152 int32_t positionMs = 0; 153 listener->getCurrentPosition(&positionMs); 154 positionUs = positionMs * 1000; 155 156 if (timeUs <= positionUs + kAdjustmentProcessingTimeUs) { 157 delayUs = 0; 158 } else { 159 delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs; 160 } 161 sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id()); 162 msg->setInt32("generation", mSendSubtitleGeneration); 163 if (parcel != NULL) { 164 msg->setObject("subtitle", parcel); 165 } 166 msg->post(delayUs); 167 } 168} 169 170void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) { 171 sp<MediaPlayerBase> listener = mListener.promote(); 172 if (listener != NULL) { 173 if (parcel != NULL && (parcel->dataSize() > 0)) { 174 listener->sendEvent(msg, 0, 0, parcel); 175 } else { // send an empty timed text to clear the screen 176 listener->sendEvent(msg); 177 } 178 } 179} 180 181} // namespace android 182