TimedTextPlayer.cpp revision bae00e73c6d1d87cc5fd42b50f95d1d9572162ea
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; 34static const int64_t kWaitTimeUsToRetryRead = 100000ll; 35 36TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener) 37 : mListener(listener), 38 mSource(NULL), 39 mSendSubtitleGeneration(0) { 40} 41 42TimedTextPlayer::~TimedTextPlayer() { 43 if (mSource != NULL) { 44 mSource->stop(); 45 mSource.clear(); 46 mSource = NULL; 47 } 48} 49 50void TimedTextPlayer::start() { 51 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 52 msg->setInt64("seekTimeUs", -1); 53 msg->post(); 54} 55 56void TimedTextPlayer::pause() { 57 (new AMessage(kWhatPause, id()))->post(); 58} 59 60void TimedTextPlayer::seekToAsync(int64_t timeUs) { 61 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 62 msg->setInt64("seekTimeUs", timeUs); 63 msg->post(); 64} 65 66void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) { 67 sp<AMessage> msg = new AMessage(kWhatSetSource, id()); 68 msg->setObject("source", source); 69 msg->post(); 70} 71 72void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) { 73 switch (msg->what()) { 74 case kWhatPause: { 75 mSendSubtitleGeneration++; 76 break; 77 } 78 case kWhatSeek: { 79 int64_t seekTimeUs = 0; 80 msg->findInt64("seekTimeUs", &seekTimeUs); 81 if (seekTimeUs < 0) { 82 sp<MediaPlayerBase> listener = mListener.promote(); 83 if (listener != NULL) { 84 int32_t positionMs = 0; 85 listener->getCurrentPosition(&positionMs); 86 seekTimeUs = positionMs * 1000ll; 87 } 88 } 89 doSeekAndRead(seekTimeUs); 90 break; 91 } 92 case kWhatSendSubtitle: { 93 int32_t generation; 94 CHECK(msg->findInt32("generation", &generation)); 95 if (generation != mSendSubtitleGeneration) { 96 // Drop obsolete msg. 97 break; 98 } 99 sp<RefBase> obj; 100 msg->findObject("subtitle", &obj); 101 if (obj != NULL) { 102 sp<ParcelEvent> parcelEvent; 103 parcelEvent = static_cast<ParcelEvent*>(obj.get()); 104 notifyListener(&(parcelEvent->parcel)); 105 } else { 106 notifyListener(); 107 } 108 doRead(); 109 break; 110 } 111 case kWhatSetSource: { 112 sp<RefBase> obj; 113 msg->findObject("source", &obj); 114 if (obj == NULL) break; 115 if (mSource != NULL) { 116 mSource->stop(); 117 } 118 mSource = static_cast<TimedTextSource*>(obj.get()); 119 status_t err = mSource->start(); 120 if (err != OK) { 121 notifyError(err); 122 break; 123 } 124 Parcel parcel; 125 err = mSource->extractGlobalDescriptions(&parcel); 126 if (err != OK) { 127 notifyError(err); 128 break; 129 } 130 notifyListener(&parcel); 131 break; 132 } 133 } 134} 135 136void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) { 137 MediaSource::ReadOptions options; 138 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 139 doRead(&options); 140} 141 142void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) { 143 int64_t startTimeUs = 0; 144 int64_t endTimeUs = 0; 145 sp<ParcelEvent> parcelEvent = new ParcelEvent(); 146 status_t err = mSource->read(&startTimeUs, &endTimeUs, 147 &(parcelEvent->parcel), options); 148 if (err == WOULD_BLOCK) { 149 postTextEventDelayUs(NULL, kWaitTimeUsToRetryRead); 150 return; 151 } else if (err != OK) { 152 notifyError(err); 153 return; 154 } 155 156 postTextEvent(parcelEvent, startTimeUs); 157 if (endTimeUs > 0) { 158 CHECK_GE(endTimeUs, startTimeUs); 159 // send an empty timed text to clear the subtitle when it reaches to the 160 // end time. 161 postTextEvent(NULL, endTimeUs); 162 } 163} 164 165void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) { 166 sp<MediaPlayerBase> listener = mListener.promote(); 167 if (listener != NULL) { 168 int64_t positionUs, delayUs; 169 int32_t positionMs = 0; 170 listener->getCurrentPosition(&positionMs); 171 positionUs = positionMs * 1000ll; 172 173 if (timeUs <= positionUs + kAdjustmentProcessingTimeUs) { 174 delayUs = 0; 175 } else { 176 delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs; 177 } 178 postTextEventDelayUs(parcel, delayUs); 179 } 180} 181 182void TimedTextPlayer::postTextEventDelayUs(const sp<ParcelEvent>& parcel, int64_t delayUs) { 183 sp<MediaPlayerBase> listener = mListener.promote(); 184 if (listener != NULL) { 185 sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id()); 186 msg->setInt32("generation", mSendSubtitleGeneration); 187 if (parcel != NULL) { 188 msg->setObject("subtitle", parcel); 189 } 190 msg->post(delayUs); 191 } 192} 193 194void TimedTextPlayer::notifyError(int error) { 195 sp<MediaPlayerBase> listener = mListener.promote(); 196 if (listener != NULL) { 197 listener->sendEvent(MEDIA_INFO, MEDIA_INFO_TIMED_TEXT_ERROR, error); 198 } 199} 200 201void TimedTextPlayer::notifyListener(const Parcel *parcel) { 202 sp<MediaPlayerBase> listener = mListener.promote(); 203 if (listener != NULL) { 204 if (parcel != NULL && (parcel->dataSize() > 0)) { 205 listener->sendEvent(MEDIA_TIMED_TEXT, 0, 0, parcel); 206 } else { // send an empty timed text to clear the screen 207 listener->sendEvent(MEDIA_TIMED_TEXT); 208 } 209 } 210} 211 212} // namespace android 213