NuPlayer.cpp revision 5bc087c573c70c84c6a39946457590b42d392a33
1/* 2 * Copyright (C) 2010 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 "NuPlayer" 19#include <utils/Log.h> 20 21#include "NuPlayer.h" 22 23#include "HTTPLiveSource.h" 24#include "NuPlayerDecoder.h" 25#include "NuPlayerRenderer.h" 26#include "NuPlayerSource.h" 27#include "StreamingSource.h" 28 29#include "ATSParser.h" 30 31#include <media/stagefright/foundation/hexdump.h> 32#include <media/stagefright/foundation/ABuffer.h> 33#include <media/stagefright/foundation/ADebug.h> 34#include <media/stagefright/foundation/AMessage.h> 35#include <media/stagefright/ACodec.h> 36#include <media/stagefright/MediaErrors.h> 37#include <media/stagefright/MetaData.h> 38#include <surfaceflinger/Surface.h> 39 40namespace android { 41 42//////////////////////////////////////////////////////////////////////////////// 43 44NuPlayer::NuPlayer() 45 : mAudioEOS(false), 46 mVideoEOS(false), 47 mScanSourcesPending(false), 48 mFlushingAudio(NONE), 49 mFlushingVideo(NONE) { 50} 51 52NuPlayer::~NuPlayer() { 53} 54 55void NuPlayer::setListener(const wp<MediaPlayerBase> &listener) { 56 mListener = listener; 57} 58 59void NuPlayer::setDataSource(const sp<IStreamSource> &source) { 60 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 61 62 msg->setObject("source", new StreamingSource(source)); 63 msg->post(); 64} 65 66void NuPlayer::setDataSource( 67 const char *url, const KeyedVector<String8, String8> *headers) { 68 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 69 70 msg->setObject("source", new HTTPLiveSource(url)); 71 msg->post(); 72} 73 74void NuPlayer::setVideoSurface(const sp<Surface> &surface) { 75 sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, id()); 76 msg->setObject("surface", surface); 77 msg->post(); 78} 79 80void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) { 81 sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id()); 82 msg->setObject("sink", sink); 83 msg->post(); 84} 85 86void NuPlayer::start() { 87 (new AMessage(kWhatStart, id()))->post(); 88} 89 90// static 91bool NuPlayer::IsFlushingState(FlushStatus state, bool *formatChange) { 92 switch (state) { 93 case FLUSHING_DECODER: 94 if (formatChange != NULL) { 95 *formatChange = false; 96 } 97 return true; 98 99 case FLUSHING_DECODER_FORMATCHANGE: 100 if (formatChange != NULL) { 101 *formatChange = true; 102 } 103 return true; 104 105 default: 106 return false; 107 } 108} 109 110void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { 111 switch (msg->what()) { 112 case kWhatSetDataSource: 113 { 114 LOGI("kWhatSetDataSource"); 115 116 CHECK(mSource == NULL); 117 118 sp<RefBase> obj; 119 CHECK(msg->findObject("source", &obj)); 120 121 mSource = static_cast<Source *>(obj.get()); 122 break; 123 } 124 125 case kWhatSetVideoSurface: 126 { 127 LOGI("kWhatSetVideoSurface"); 128 129 sp<RefBase> obj; 130 CHECK(msg->findObject("surface", &obj)); 131 132 mSurface = static_cast<Surface *>(obj.get()); 133 break; 134 } 135 136 case kWhatSetAudioSink: 137 { 138 LOGI("kWhatSetAudioSink"); 139 140 sp<RefBase> obj; 141 CHECK(msg->findObject("sink", &obj)); 142 143 mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); 144 break; 145 } 146 147 case kWhatStart: 148 { 149 mSource->start(); 150 151 mRenderer = new Renderer( 152 mAudioSink, 153 new AMessage(kWhatRendererNotify, id())); 154 155 looper()->registerHandler(mRenderer); 156 157 (new AMessage(kWhatScanSources, id()))->post(); 158 mScanSourcesPending = true; 159 break; 160 } 161 162 case kWhatScanSources: 163 { 164 mScanSourcesPending = false; 165 166 instantiateDecoder(false, &mVideoDecoder); 167 168 if (mAudioSink != NULL) { 169 instantiateDecoder(true, &mAudioDecoder); 170 } 171 172 if (!mSource->feedMoreTSData()) { 173 break; 174 } 175 176 if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 177 msg->post(100000ll); 178 mScanSourcesPending = true; 179 } 180 break; 181 } 182 183 case kWhatVideoNotify: 184 case kWhatAudioNotify: 185 { 186 bool audio = msg->what() == kWhatAudioNotify; 187 188 sp<AMessage> codecRequest; 189 CHECK(msg->findMessage("codec-request", &codecRequest)); 190 191 int32_t what; 192 CHECK(codecRequest->findInt32("what", &what)); 193 194 if (what == ACodec::kWhatFillThisBuffer) { 195 status_t err = feedDecoderInputData( 196 audio, codecRequest); 197 198 if (err == -EWOULDBLOCK) { 199 if (mSource->feedMoreTSData()) { 200 msg->post(); 201 } 202 } 203 } else if (what == ACodec::kWhatEOS) { 204 mRenderer->queueEOS(audio, ERROR_END_OF_STREAM); 205 } else if (what == ACodec::kWhatFlushCompleted) { 206 bool formatChange; 207 208 if (audio) { 209 CHECK(IsFlushingState(mFlushingAudio, &formatChange)); 210 mFlushingAudio = FLUSHED; 211 } else { 212 CHECK(IsFlushingState(mFlushingVideo, &formatChange)); 213 mFlushingVideo = FLUSHED; 214 } 215 216 LOGI("decoder %s flush completed", audio ? "audio" : "video"); 217 218 if (formatChange) { 219 LOGI("initiating %s decoder shutdown", 220 audio ? "audio" : "video"); 221 222 (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); 223 224 if (audio) { 225 mFlushingAudio = SHUTTING_DOWN_DECODER; 226 } else { 227 mFlushingVideo = SHUTTING_DOWN_DECODER; 228 } 229 } 230 231 finishFlushIfPossible(); 232 } else if (what == ACodec::kWhatOutputFormatChanged) { 233 CHECK(audio); 234 235 int32_t numChannels; 236 CHECK(codecRequest->findInt32("channel-count", &numChannels)); 237 238 int32_t sampleRate; 239 CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); 240 241 LOGI("Audio output format changed to %d Hz, %d channels", 242 sampleRate, numChannels); 243 244 mAudioSink->close(); 245 CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK); 246 mAudioSink->start(); 247 248 mRenderer->signalAudioSinkChanged(); 249 } else if (what == ACodec::kWhatShutdownCompleted) { 250 LOGI("%s shutdown completed", audio ? "audio" : "video"); 251 if (audio) { 252 mAudioDecoder.clear(); 253 254 CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); 255 mFlushingAudio = SHUT_DOWN; 256 } else { 257 mVideoDecoder.clear(); 258 259 CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); 260 mFlushingVideo = SHUT_DOWN; 261 } 262 263 finishFlushIfPossible(); 264 } else { 265 CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer); 266 267 renderBuffer(audio, codecRequest); 268 } 269 270 break; 271 } 272 273 case kWhatRendererNotify: 274 { 275 int32_t what; 276 CHECK(msg->findInt32("what", &what)); 277 278 if (what == Renderer::kWhatEOS) { 279 int32_t audio; 280 CHECK(msg->findInt32("audio", &audio)); 281 282 if (audio) { 283 mAudioEOS = true; 284 } else { 285 mVideoEOS = true; 286 } 287 288 LOGI("reached %s EOS", audio ? "audio" : "video"); 289 290 if ((mAudioEOS || mAudioDecoder == NULL) 291 && (mVideoEOS || mVideoDecoder == NULL)) { 292 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 293 } 294 } else { 295 CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete); 296 297 int32_t audio; 298 CHECK(msg->findInt32("audio", &audio)); 299 300 LOGI("renderer %s flush completed.", audio ? "audio" : "video"); 301 } 302 break; 303 } 304 305 case kWhatMoreDataQueued: 306 { 307 break; 308 } 309 310 default: 311 TRESPASS(); 312 break; 313 } 314} 315 316void NuPlayer::finishFlushIfPossible() { 317 if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { 318 return; 319 } 320 321 if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) { 322 return; 323 } 324 325 LOGI("both audio and video are flushed now."); 326 327 mRenderer->signalTimeDiscontinuity(); 328 329 bool scanSourcesAgain = false; 330 331 if (mFlushingAudio == SHUT_DOWN) { 332 scanSourcesAgain = true; 333 } else if (mAudioDecoder != NULL) { 334 mAudioDecoder->signalResume(); 335 } 336 337 if (mFlushingVideo == SHUT_DOWN) { 338 scanSourcesAgain = true; 339 } else if (mVideoDecoder != NULL) { 340 mVideoDecoder->signalResume(); 341 } 342 343 mFlushingAudio = NONE; 344 mFlushingVideo = NONE; 345 346 if (scanSourcesAgain && !mScanSourcesPending) { 347 mScanSourcesPending = true; 348 (new AMessage(kWhatScanSources, id()))->post(); 349 } 350} 351 352status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { 353 if (*decoder != NULL) { 354 return OK; 355 } 356 357 sp<MetaData> meta = mSource->getFormat(audio); 358 359 if (meta == NULL) { 360 return -EWOULDBLOCK; 361 } 362 363 sp<AMessage> notify = 364 new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, 365 id()); 366 367 *decoder = new Decoder(notify, audio ? NULL : mSurface); 368 looper()->registerHandler(*decoder); 369 370 (*decoder)->configure(meta); 371 372 return OK; 373} 374 375status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { 376 sp<AMessage> reply; 377 CHECK(msg->findMessage("reply", &reply)); 378 379 if ((audio && IsFlushingState(mFlushingAudio)) 380 || (!audio && IsFlushingState(mFlushingVideo))) { 381 reply->setInt32("err", INFO_DISCONTINUITY); 382 reply->post(); 383 return OK; 384 } 385 386 sp<ABuffer> accessUnit; 387 status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); 388 389 if (err == -EWOULDBLOCK) { 390 return err; 391 } else if (err != OK) { 392 if (err == INFO_DISCONTINUITY) { 393 int32_t type; 394 CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); 395 396 bool formatChange = 397 type == ATSParser::DISCONTINUITY_FORMATCHANGE; 398 399 LOGI("%s discontinuity (formatChange=%d)", 400 audio ? "audio" : "video", formatChange); 401 402 (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); 403 mRenderer->flush(audio); 404 405 if (audio) { 406 CHECK(mFlushingAudio == NONE 407 || mFlushingAudio == AWAITING_DISCONTINUITY); 408 409 mFlushingAudio = formatChange 410 ? FLUSHING_DECODER_FORMATCHANGE : FLUSHING_DECODER; 411 412 if (mFlushingVideo == NONE) { 413 mFlushingVideo = (mVideoDecoder != NULL) 414 ? AWAITING_DISCONTINUITY 415 : FLUSHED; 416 } 417 } else { 418 CHECK(mFlushingVideo == NONE 419 || mFlushingVideo == AWAITING_DISCONTINUITY); 420 421 mFlushingVideo = formatChange 422 ? FLUSHING_DECODER_FORMATCHANGE : FLUSHING_DECODER; 423 424 if (mFlushingAudio == NONE) { 425 mFlushingAudio = (mAudioDecoder != NULL) 426 ? AWAITING_DISCONTINUITY 427 : FLUSHED; 428 } 429 } 430 } 431 432 reply->setInt32("err", err); 433 reply->post(); 434 return OK; 435 } 436 437 LOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); 438 439#if 0 440 int64_t mediaTimeUs; 441 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); 442 LOGI("feeding %s input buffer at media time %.2f secs", 443 audio ? "audio" : "video", 444 mediaTimeUs / 1E6); 445#endif 446 447 reply->setObject("buffer", accessUnit); 448 reply->post(); 449 450 return OK; 451} 452 453void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { 454 LOGV("renderBuffer %s", audio ? "audio" : "video"); 455 456 sp<AMessage> reply; 457 CHECK(msg->findMessage("reply", &reply)); 458 459 sp<RefBase> obj; 460 CHECK(msg->findObject("buffer", &obj)); 461 462 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get()); 463 464 mRenderer->queueBuffer(audio, buffer, reply); 465} 466 467void NuPlayer::notifyListener(int msg, int ext1, int ext2) { 468 if (mListener == NULL) { 469 return; 470 } 471 472 sp<MediaPlayerBase> listener = mListener.promote(); 473 474 if (listener == NULL) { 475 return; 476 } 477 478 listener->sendEvent(msg, ext1, ext2); 479} 480 481} // namespace android 482