blob: 3b3fca25e06121970dc4d3a09ad6121490a40b3a [file] [log] [blame]
Andreas Huberf9334412010-12-15 15:17:42 -08001/*
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 "NuPlayerRenderer"
19#include <utils/Log.h>
20
21#include "NuPlayerRenderer.h"
22
23#include <media/stagefright/foundation/ABuffer.h>
24#include <media/stagefright/foundation/ADebug.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080025#include <media/stagefright/foundation/AMessage.h>
Andreas Huberf9334412010-12-15 15:17:42 -080026
27namespace android {
28
Andreas Huber714aa7b2011-09-13 08:28:38 -070029// static
30const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
31
Andreas Huberf9334412010-12-15 15:17:42 -080032NuPlayer::Renderer::Renderer(
33 const sp<MediaPlayerBase::AudioSink> &sink,
34 const sp<AMessage> &notify)
35 : mAudioSink(sink),
36 mNotify(notify),
37 mNumFramesWritten(0),
38 mDrainAudioQueuePending(false),
39 mDrainVideoQueuePending(false),
40 mAudioQueueGeneration(0),
41 mVideoQueueGeneration(0),
42 mAnchorTimeMediaUs(-1),
43 mAnchorTimeRealUs(-1),
44 mFlushingAudio(false),
45 mFlushingVideo(false),
Andreas Huberbc7f5b22011-01-21 10:15:23 -080046 mHasAudio(false),
47 mHasVideo(false),
48 mSyncQueues(false),
Andreas Huber714aa7b2011-09-13 08:28:38 -070049 mPaused(false),
50 mLastPositionUpdateUs(-1ll) {
Andreas Huberf9334412010-12-15 15:17:42 -080051}
52
53NuPlayer::Renderer::~Renderer() {
54}
55
56void NuPlayer::Renderer::queueBuffer(
57 bool audio,
58 const sp<ABuffer> &buffer,
59 const sp<AMessage> &notifyConsumed) {
60 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
61 msg->setInt32("audio", static_cast<int32_t>(audio));
62 msg->setObject("buffer", buffer);
63 msg->setMessage("notifyConsumed", notifyConsumed);
64 msg->post();
65}
66
67void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
68 CHECK_NE(finalResult, (status_t)OK);
69
70 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
71 msg->setInt32("audio", static_cast<int32_t>(audio));
72 msg->setInt32("finalResult", finalResult);
73 msg->post();
74}
75
76void NuPlayer::Renderer::flush(bool audio) {
77 {
78 Mutex::Autolock autoLock(mFlushLock);
79 if (audio) {
80 CHECK(!mFlushingAudio);
81 mFlushingAudio = true;
82 } else {
83 CHECK(!mFlushingVideo);
84 mFlushingVideo = true;
85 }
86 }
87
88 sp<AMessage> msg = new AMessage(kWhatFlush, id());
89 msg->setInt32("audio", static_cast<int32_t>(audio));
90 msg->post();
91}
92
93void NuPlayer::Renderer::signalTimeDiscontinuity() {
94 CHECK(mAudioQueue.empty());
95 CHECK(mVideoQueue.empty());
96 mAnchorTimeMediaUs = -1;
97 mAnchorTimeRealUs = -1;
Andreas Huber3831a062010-12-21 10:22:33 -080098 mSyncQueues = mHasAudio && mHasVideo;
Andreas Huberf9334412010-12-15 15:17:42 -080099}
100
Andreas Huberb4082222011-01-20 15:23:04 -0800101void NuPlayer::Renderer::pause() {
102 (new AMessage(kWhatPause, id()))->post();
103}
104
105void NuPlayer::Renderer::resume() {
106 (new AMessage(kWhatResume, id()))->post();
107}
108
Andreas Huberf9334412010-12-15 15:17:42 -0800109void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
110 switch (msg->what()) {
111 case kWhatDrainAudioQueue:
112 {
113 int32_t generation;
114 CHECK(msg->findInt32("generation", &generation));
115 if (generation != mAudioQueueGeneration) {
116 break;
117 }
118
119 mDrainAudioQueuePending = false;
120
Andreas Huber078cfcf2011-09-15 12:25:04 -0700121 if (onDrainAudioQueue()) {
122 uint32_t numFramesPlayed;
123 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
124 (status_t)OK);
Andreas Huberf9334412010-12-15 15:17:42 -0800125
Andreas Huber078cfcf2011-09-15 12:25:04 -0700126 uint32_t numFramesPendingPlayout =
127 mNumFramesWritten - numFramesPlayed;
128
129 // This is how long the audio sink will have data to
130 // play back.
131 int64_t delayUs =
132 mAudioSink->msecsPerFrame()
133 * numFramesPendingPlayout * 1000ll;
134
135 // Let's give it more data after about half that time
136 // has elapsed.
137 postDrainAudioQueue(delayUs / 2);
138 }
Andreas Huberf9334412010-12-15 15:17:42 -0800139 break;
140 }
141
142 case kWhatDrainVideoQueue:
143 {
144 int32_t generation;
145 CHECK(msg->findInt32("generation", &generation));
146 if (generation != mVideoQueueGeneration) {
147 break;
148 }
149
150 mDrainVideoQueuePending = false;
151
152 onDrainVideoQueue();
153
154 postDrainVideoQueue();
155 break;
156 }
157
158 case kWhatQueueBuffer:
159 {
160 onQueueBuffer(msg);
161 break;
162 }
163
164 case kWhatQueueEOS:
165 {
166 onQueueEOS(msg);
167 break;
168 }
169
170 case kWhatFlush:
171 {
172 onFlush(msg);
173 break;
174 }
175
Andreas Huber3831a062010-12-21 10:22:33 -0800176 case kWhatAudioSinkChanged:
177 {
178 onAudioSinkChanged();
179 break;
180 }
181
Andreas Huberb4082222011-01-20 15:23:04 -0800182 case kWhatPause:
183 {
184 onPause();
185 break;
186 }
187
188 case kWhatResume:
189 {
190 onResume();
191 break;
192 }
193
Andreas Huberf9334412010-12-15 15:17:42 -0800194 default:
195 TRESPASS();
196 break;
197 }
198}
199
Andreas Huber078cfcf2011-09-15 12:25:04 -0700200void NuPlayer::Renderer::postDrainAudioQueue(int64_t delayUs) {
Andreas Huberb4082222011-01-20 15:23:04 -0800201 if (mDrainAudioQueuePending || mSyncQueues || mPaused) {
Andreas Huberf9334412010-12-15 15:17:42 -0800202 return;
203 }
204
205 if (mAudioQueue.empty()) {
206 return;
207 }
208
209 mDrainAudioQueuePending = true;
210 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
211 msg->setInt32("generation", mAudioQueueGeneration);
Andreas Huber078cfcf2011-09-15 12:25:04 -0700212 msg->post(delayUs);
Andreas Huberf9334412010-12-15 15:17:42 -0800213}
214
Andreas Huber3831a062010-12-21 10:22:33 -0800215void NuPlayer::Renderer::signalAudioSinkChanged() {
216 (new AMessage(kWhatAudioSinkChanged, id()))->post();
217}
218
Andreas Huber078cfcf2011-09-15 12:25:04 -0700219bool NuPlayer::Renderer::onDrainAudioQueue() {
220 uint32_t numFramesPlayed;
221 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
Andreas Huberc92fd242011-08-16 13:48:44 -0700222
Andreas Huber078cfcf2011-09-15 12:25:04 -0700223 ssize_t numFramesAvailableToWrite =
224 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
225
226#if 0
227 if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
228 LOGI("audio sink underrun");
229 } else {
230 LOGV("audio queue has %d frames left to play",
231 mAudioSink->frameCount() - numFramesAvailableToWrite);
232 }
233#endif
234
235 size_t numBytesAvailableToWrite =
236 numFramesAvailableToWrite * mAudioSink->frameSize();
237
238 while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
Andreas Huberc92fd242011-08-16 13:48:44 -0700239 QueueEntry *entry = &*mAudioQueue.begin();
240
241 if (entry->mBuffer == NULL) {
242 // EOS
243
244 notifyEOS(true /* audio */, entry->mFinalResult);
245
246 mAudioQueue.erase(mAudioQueue.begin());
247 entry = NULL;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700248 return false;
Eric Laurent9b7d9502011-03-21 11:49:00 -0700249 }
250
Andreas Huberf9334412010-12-15 15:17:42 -0800251 if (entry->mOffset == 0) {
252 int64_t mediaTimeUs;
253 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
254
255 LOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
256
257 mAnchorTimeMediaUs = mediaTimeUs;
258
259 uint32_t numFramesPlayed;
260 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
261
262 uint32_t numFramesPendingPlayout =
263 mNumFramesWritten - numFramesPlayed;
264
265 int64_t realTimeOffsetUs =
266 (mAudioSink->latency() / 2 /* XXX */
267 + numFramesPendingPlayout
268 * mAudioSink->msecsPerFrame()) * 1000ll;
269
270 // LOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs);
271
272 mAnchorTimeRealUs =
273 ALooper::GetNowUs() + realTimeOffsetUs;
274 }
275
276 size_t copy = entry->mBuffer->size() - entry->mOffset;
277 if (copy > numBytesAvailableToWrite) {
278 copy = numBytesAvailableToWrite;
279 }
280
281 CHECK_EQ(mAudioSink->write(
282 entry->mBuffer->data() + entry->mOffset, copy),
283 (ssize_t)copy);
284
285 entry->mOffset += copy;
286 if (entry->mOffset == entry->mBuffer->size()) {
287 entry->mNotifyConsumed->post();
288 mAudioQueue.erase(mAudioQueue.begin());
Eric Laurent9b7d9502011-03-21 11:49:00 -0700289
Andreas Huberf9334412010-12-15 15:17:42 -0800290 entry = NULL;
291 }
292
Andreas Huber078cfcf2011-09-15 12:25:04 -0700293 numBytesAvailableToWrite -= copy;
294 size_t copiedFrames = copy / mAudioSink->frameSize();
295 mNumFramesWritten += copiedFrames;
Andreas Huberf9334412010-12-15 15:17:42 -0800296 }
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800297
298 notifyPosition();
Andreas Huber078cfcf2011-09-15 12:25:04 -0700299
300 return !mAudioQueue.empty();
Andreas Huberf9334412010-12-15 15:17:42 -0800301}
302
303void NuPlayer::Renderer::postDrainVideoQueue() {
Andreas Huberb4082222011-01-20 15:23:04 -0800304 if (mDrainVideoQueuePending || mSyncQueues || mPaused) {
Andreas Huberf9334412010-12-15 15:17:42 -0800305 return;
306 }
307
308 if (mVideoQueue.empty()) {
309 return;
310 }
311
312 QueueEntry &entry = *mVideoQueue.begin();
313
314 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
315 msg->setInt32("generation", mVideoQueueGeneration);
316
317 int64_t delayUs;
318
319 if (entry.mBuffer == NULL) {
320 // EOS doesn't carry a timestamp.
321 delayUs = 0;
322 } else {
323 int64_t mediaTimeUs;
324 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
325
326 if (mAnchorTimeMediaUs < 0) {
327 delayUs = 0;
328
Andreas Huber3831a062010-12-21 10:22:33 -0800329 if (!mHasAudio) {
Andreas Huberf9334412010-12-15 15:17:42 -0800330 mAnchorTimeMediaUs = mediaTimeUs;
331 mAnchorTimeRealUs = ALooper::GetNowUs();
332 }
333 } else {
334 int64_t realTimeUs =
335 (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs;
336
337 delayUs = realTimeUs - ALooper::GetNowUs();
338 }
339 }
340
341 msg->post(delayUs);
342
343 mDrainVideoQueuePending = true;
344}
345
346void NuPlayer::Renderer::onDrainVideoQueue() {
347 if (mVideoQueue.empty()) {
348 return;
349 }
350
351 QueueEntry *entry = &*mVideoQueue.begin();
352
353 if (entry->mBuffer == NULL) {
354 // EOS
355
Andreas Huberc92fd242011-08-16 13:48:44 -0700356 notifyEOS(false /* audio */, entry->mFinalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800357
358 mVideoQueue.erase(mVideoQueue.begin());
359 entry = NULL;
360 return;
361 }
362
363#if 0
364 int64_t mediaTimeUs;
365 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
366
Andreas Huber078cfcf2011-09-15 12:25:04 -0700367 int64_t realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
368 int64_t lateByUs = ALooper::GetNowUs() - realTimeUs;
369
370 if (lateByUs > 40000) {
371 LOGI("video late by %lld us (%.2f secs)", lateByUs, lateByUs / 1E6);
372 } else {
373 LOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
374 }
Andreas Huberf9334412010-12-15 15:17:42 -0800375#endif
376
377 entry->mNotifyConsumed->setInt32("render", true);
378 entry->mNotifyConsumed->post();
379 mVideoQueue.erase(mVideoQueue.begin());
380 entry = NULL;
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800381
382 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800383}
384
Andreas Huberc92fd242011-08-16 13:48:44 -0700385void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
Andreas Huberf9334412010-12-15 15:17:42 -0800386 sp<AMessage> notify = mNotify->dup();
387 notify->setInt32("what", kWhatEOS);
388 notify->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huberc92fd242011-08-16 13:48:44 -0700389 notify->setInt32("finalResult", finalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800390 notify->post();
391}
392
393void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
394 int32_t audio;
395 CHECK(msg->findInt32("audio", &audio));
396
Andreas Huberbc7f5b22011-01-21 10:15:23 -0800397 if (audio) {
398 mHasAudio = true;
399 } else {
400 mHasVideo = true;
401 }
402
Andreas Huberf9334412010-12-15 15:17:42 -0800403 if (dropBufferWhileFlushing(audio, msg)) {
404 return;
405 }
406
407 sp<RefBase> obj;
408 CHECK(msg->findObject("buffer", &obj));
409 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
410
411 sp<AMessage> notifyConsumed;
412 CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
413
414 QueueEntry entry;
415 entry.mBuffer = buffer;
416 entry.mNotifyConsumed = notifyConsumed;
417 entry.mOffset = 0;
418 entry.mFinalResult = OK;
419
420 if (audio) {
421 mAudioQueue.push_back(entry);
422 postDrainAudioQueue();
423 } else {
424 mVideoQueue.push_back(entry);
425 postDrainVideoQueue();
426 }
427
Andreas Hubercb67cd12011-08-26 16:02:19 -0700428 if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
429 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800430 }
Andreas Hubercb67cd12011-08-26 16:02:19 -0700431
432 sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
433 sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
434
435 if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
436 // EOS signalled on either queue.
437 syncQueuesDone();
438 return;
439 }
440
441 int64_t firstAudioTimeUs;
442 int64_t firstVideoTimeUs;
443 CHECK(firstAudioBuffer->meta()
444 ->findInt64("timeUs", &firstAudioTimeUs));
445 CHECK(firstVideoBuffer->meta()
446 ->findInt64("timeUs", &firstVideoTimeUs));
447
448 int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
449
450 LOGV("queueDiff = %.2f secs", diff / 1E6);
451
452 if (diff > 100000ll) {
453 // Audio data starts More than 0.1 secs before video.
454 // Drop some audio.
455
456 (*mAudioQueue.begin()).mNotifyConsumed->post();
457 mAudioQueue.erase(mAudioQueue.begin());
458 return;
459 }
460
461 syncQueuesDone();
Andreas Huberf9334412010-12-15 15:17:42 -0800462}
463
464void NuPlayer::Renderer::syncQueuesDone() {
465 if (!mSyncQueues) {
466 return;
467 }
468
469 mSyncQueues = false;
470
471 if (!mAudioQueue.empty()) {
472 postDrainAudioQueue();
473 }
474
475 if (!mVideoQueue.empty()) {
476 postDrainVideoQueue();
477 }
478}
479
480void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
481 int32_t audio;
482 CHECK(msg->findInt32("audio", &audio));
483
484 if (dropBufferWhileFlushing(audio, msg)) {
485 return;
486 }
487
488 int32_t finalResult;
489 CHECK(msg->findInt32("finalResult", &finalResult));
490
491 QueueEntry entry;
492 entry.mOffset = 0;
493 entry.mFinalResult = finalResult;
494
495 if (audio) {
496 mAudioQueue.push_back(entry);
497 postDrainAudioQueue();
498 } else {
499 mVideoQueue.push_back(entry);
500 postDrainVideoQueue();
501 }
502}
503
504void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
505 int32_t audio;
506 CHECK(msg->findInt32("audio", &audio));
507
508 // If we're currently syncing the queues, i.e. dropping audio while
509 // aligning the first audio/video buffer times and only one of the
510 // two queues has data, we may starve that queue by not requesting
511 // more buffers from the decoder. If the other source then encounters
512 // a discontinuity that leads to flushing, we'll never find the
513 // corresponding discontinuity on the other queue.
514 // Therefore we'll stop syncing the queues if at least one of them
515 // is flushed.
516 syncQueuesDone();
517
518 if (audio) {
519 flushQueue(&mAudioQueue);
520
521 Mutex::Autolock autoLock(mFlushLock);
522 mFlushingAudio = false;
523
524 mDrainAudioQueuePending = false;
525 ++mAudioQueueGeneration;
526 } else {
527 flushQueue(&mVideoQueue);
528
529 Mutex::Autolock autoLock(mFlushLock);
530 mFlushingVideo = false;
531
532 mDrainVideoQueuePending = false;
533 ++mVideoQueueGeneration;
534 }
535
536 notifyFlushComplete(audio);
537}
538
539void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
540 while (!queue->empty()) {
541 QueueEntry *entry = &*queue->begin();
542
543 if (entry->mBuffer != NULL) {
544 entry->mNotifyConsumed->post();
545 }
546
547 queue->erase(queue->begin());
548 entry = NULL;
549 }
550}
551
552void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
553 sp<AMessage> notify = mNotify->dup();
554 notify->setInt32("what", kWhatFlushComplete);
555 notify->setInt32("audio", static_cast<int32_t>(audio));
556 notify->post();
557}
558
559bool NuPlayer::Renderer::dropBufferWhileFlushing(
560 bool audio, const sp<AMessage> &msg) {
561 bool flushing = false;
562
563 {
564 Mutex::Autolock autoLock(mFlushLock);
565 if (audio) {
566 flushing = mFlushingAudio;
567 } else {
568 flushing = mFlushingVideo;
569 }
570 }
571
572 if (!flushing) {
573 return false;
574 }
575
576 sp<AMessage> notifyConsumed;
577 if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
578 notifyConsumed->post();
579 }
580
581 return true;
582}
583
Andreas Huber3831a062010-12-21 10:22:33 -0800584void NuPlayer::Renderer::onAudioSinkChanged() {
585 CHECK(!mDrainAudioQueuePending);
586 mNumFramesWritten = 0;
587}
588
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800589void NuPlayer::Renderer::notifyPosition() {
590 if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) {
591 return;
592 }
593
594 int64_t nowUs = ALooper::GetNowUs();
Andreas Huber714aa7b2011-09-13 08:28:38 -0700595
596 if (mLastPositionUpdateUs >= 0
597 && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
598 return;
599 }
600 mLastPositionUpdateUs = nowUs;
601
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800602 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
603
604 sp<AMessage> notify = mNotify->dup();
605 notify->setInt32("what", kWhatPosition);
606 notify->setInt64("positionUs", positionUs);
607 notify->post();
608}
609
Andreas Huberb4082222011-01-20 15:23:04 -0800610void NuPlayer::Renderer::onPause() {
611 CHECK(!mPaused);
612
613 mDrainAudioQueuePending = false;
614 ++mAudioQueueGeneration;
615
616 mDrainVideoQueuePending = false;
617 ++mVideoQueueGeneration;
618
619 if (mHasAudio) {
620 mAudioSink->pause();
621 }
622
623 mPaused = true;
624}
625
626void NuPlayer::Renderer::onResume() {
627 CHECK(mPaused);
628
629 if (mHasAudio) {
630 mAudioSink->start();
631 }
632
633 mPaused = false;
634
635 if (!mAudioQueue.empty()) {
636 postDrainAudioQueue();
637 }
638
639 if (!mVideoQueue.empty()) {
640 postDrainVideoQueue();
641 }
642}
643
Andreas Huberf9334412010-12-15 15:17:42 -0800644} // namespace android
645