blob: 35ed43fc441e8b2adbcd9440eb984e1a2ac84f4c [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
29NuPlayer::Renderer::Renderer(
30 const sp<MediaPlayerBase::AudioSink> &sink,
31 const sp<AMessage> &notify)
32 : mAudioSink(sink),
33 mNotify(notify),
34 mNumFramesWritten(0),
35 mDrainAudioQueuePending(false),
36 mDrainVideoQueuePending(false),
37 mAudioQueueGeneration(0),
38 mVideoQueueGeneration(0),
39 mAnchorTimeMediaUs(-1),
40 mAnchorTimeRealUs(-1),
41 mFlushingAudio(false),
42 mFlushingVideo(false),
Andreas Huberbc7f5b22011-01-21 10:15:23 -080043 mHasAudio(false),
44 mHasVideo(false),
45 mSyncQueues(false),
Andreas Huberb4082222011-01-20 15:23:04 -080046 mPaused(false) {
Andreas Huberf9334412010-12-15 15:17:42 -080047}
48
49NuPlayer::Renderer::~Renderer() {
50}
51
52void NuPlayer::Renderer::queueBuffer(
53 bool audio,
54 const sp<ABuffer> &buffer,
55 const sp<AMessage> &notifyConsumed) {
56 sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
57 msg->setInt32("audio", static_cast<int32_t>(audio));
58 msg->setObject("buffer", buffer);
59 msg->setMessage("notifyConsumed", notifyConsumed);
60 msg->post();
61}
62
63void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
64 CHECK_NE(finalResult, (status_t)OK);
65
66 sp<AMessage> msg = new AMessage(kWhatQueueEOS, id());
67 msg->setInt32("audio", static_cast<int32_t>(audio));
68 msg->setInt32("finalResult", finalResult);
69 msg->post();
70}
71
72void NuPlayer::Renderer::flush(bool audio) {
73 {
74 Mutex::Autolock autoLock(mFlushLock);
75 if (audio) {
76 CHECK(!mFlushingAudio);
77 mFlushingAudio = true;
78 } else {
79 CHECK(!mFlushingVideo);
80 mFlushingVideo = true;
81 }
82 }
83
84 sp<AMessage> msg = new AMessage(kWhatFlush, id());
85 msg->setInt32("audio", static_cast<int32_t>(audio));
86 msg->post();
87}
88
89void NuPlayer::Renderer::signalTimeDiscontinuity() {
90 CHECK(mAudioQueue.empty());
91 CHECK(mVideoQueue.empty());
92 mAnchorTimeMediaUs = -1;
93 mAnchorTimeRealUs = -1;
Andreas Huber3831a062010-12-21 10:22:33 -080094 mSyncQueues = mHasAudio && mHasVideo;
Andreas Huberf9334412010-12-15 15:17:42 -080095}
96
Andreas Huberb4082222011-01-20 15:23:04 -080097void NuPlayer::Renderer::pause() {
98 (new AMessage(kWhatPause, id()))->post();
99}
100
101void NuPlayer::Renderer::resume() {
102 (new AMessage(kWhatResume, id()))->post();
103}
104
Andreas Huberf9334412010-12-15 15:17:42 -0800105void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
106 switch (msg->what()) {
107 case kWhatDrainAudioQueue:
108 {
109 int32_t generation;
110 CHECK(msg->findInt32("generation", &generation));
111 if (generation != mAudioQueueGeneration) {
112 break;
113 }
114
115 mDrainAudioQueuePending = false;
116
117 onDrainAudioQueue();
118
119 postDrainAudioQueue();
120 break;
121 }
122
123 case kWhatDrainVideoQueue:
124 {
125 int32_t generation;
126 CHECK(msg->findInt32("generation", &generation));
127 if (generation != mVideoQueueGeneration) {
128 break;
129 }
130
131 mDrainVideoQueuePending = false;
132
133 onDrainVideoQueue();
134
135 postDrainVideoQueue();
136 break;
137 }
138
139 case kWhatQueueBuffer:
140 {
141 onQueueBuffer(msg);
142 break;
143 }
144
145 case kWhatQueueEOS:
146 {
147 onQueueEOS(msg);
148 break;
149 }
150
151 case kWhatFlush:
152 {
153 onFlush(msg);
154 break;
155 }
156
Andreas Huber3831a062010-12-21 10:22:33 -0800157 case kWhatAudioSinkChanged:
158 {
159 onAudioSinkChanged();
160 break;
161 }
162
Andreas Huberb4082222011-01-20 15:23:04 -0800163 case kWhatPause:
164 {
165 onPause();
166 break;
167 }
168
169 case kWhatResume:
170 {
171 onResume();
172 break;
173 }
174
Andreas Huberf9334412010-12-15 15:17:42 -0800175 default:
176 TRESPASS();
177 break;
178 }
179}
180
181void NuPlayer::Renderer::postDrainAudioQueue() {
Andreas Huberb4082222011-01-20 15:23:04 -0800182 if (mDrainAudioQueuePending || mSyncQueues || mPaused) {
Andreas Huberf9334412010-12-15 15:17:42 -0800183 return;
184 }
185
186 if (mAudioQueue.empty()) {
187 return;
188 }
189
190 mDrainAudioQueuePending = true;
191 sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
192 msg->setInt32("generation", mAudioQueueGeneration);
193 msg->post(10000);
194}
195
Andreas Huber3831a062010-12-21 10:22:33 -0800196void NuPlayer::Renderer::signalAudioSinkChanged() {
197 (new AMessage(kWhatAudioSinkChanged, id()))->post();
198}
199
Andreas Huberf9334412010-12-15 15:17:42 -0800200void NuPlayer::Renderer::onDrainAudioQueue() {
Andreas Huberf9334412010-12-15 15:17:42 -0800201
Eric Laurent9b7d9502011-03-21 11:49:00 -0700202 for (;;) {
Andreas Huberc92fd242011-08-16 13:48:44 -0700203 if (mAudioQueue.empty()) {
204 break;
205 }
206
207 QueueEntry *entry = &*mAudioQueue.begin();
208
209 if (entry->mBuffer == NULL) {
210 // EOS
211
212 notifyEOS(true /* audio */, entry->mFinalResult);
213
214 mAudioQueue.erase(mAudioQueue.begin());
215 entry = NULL;
216 return;
217 }
218
Eric Laurent9b7d9502011-03-21 11:49:00 -0700219 uint32_t numFramesPlayed;
220 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
Andreas Huberf9334412010-12-15 15:17:42 -0800221
Eric Laurent9b7d9502011-03-21 11:49:00 -0700222 ssize_t numFramesAvailableToWrite =
223 mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
Andreas Huberf9334412010-12-15 15:17:42 -0800224
Eric Laurent9b7d9502011-03-21 11:49:00 -0700225 size_t numBytesAvailableToWrite =
226 numFramesAvailableToWrite * mAudioSink->frameSize();
Andreas Huberf9334412010-12-15 15:17:42 -0800227
Eric Laurent9b7d9502011-03-21 11:49:00 -0700228 if (numBytesAvailableToWrite == 0) {
229 break;
230 }
231
Andreas Huberf9334412010-12-15 15:17:42 -0800232 if (entry->mOffset == 0) {
233 int64_t mediaTimeUs;
234 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
235
236 LOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
237
238 mAnchorTimeMediaUs = mediaTimeUs;
239
240 uint32_t numFramesPlayed;
241 CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
242
243 uint32_t numFramesPendingPlayout =
244 mNumFramesWritten - numFramesPlayed;
245
246 int64_t realTimeOffsetUs =
247 (mAudioSink->latency() / 2 /* XXX */
248 + numFramesPendingPlayout
249 * mAudioSink->msecsPerFrame()) * 1000ll;
250
251 // LOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs);
252
253 mAnchorTimeRealUs =
254 ALooper::GetNowUs() + realTimeOffsetUs;
255 }
256
257 size_t copy = entry->mBuffer->size() - entry->mOffset;
258 if (copy > numBytesAvailableToWrite) {
259 copy = numBytesAvailableToWrite;
260 }
261
262 CHECK_EQ(mAudioSink->write(
263 entry->mBuffer->data() + entry->mOffset, copy),
264 (ssize_t)copy);
265
266 entry->mOffset += copy;
267 if (entry->mOffset == entry->mBuffer->size()) {
268 entry->mNotifyConsumed->post();
269 mAudioQueue.erase(mAudioQueue.begin());
Eric Laurent9b7d9502011-03-21 11:49:00 -0700270
Andreas Huberf9334412010-12-15 15:17:42 -0800271 entry = NULL;
272 }
273
Andreas Huberf9334412010-12-15 15:17:42 -0800274 mNumFramesWritten += copy / mAudioSink->frameSize();
275 }
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800276
277 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800278}
279
280void NuPlayer::Renderer::postDrainVideoQueue() {
Andreas Huberb4082222011-01-20 15:23:04 -0800281 if (mDrainVideoQueuePending || mSyncQueues || mPaused) {
Andreas Huberf9334412010-12-15 15:17:42 -0800282 return;
283 }
284
285 if (mVideoQueue.empty()) {
286 return;
287 }
288
289 QueueEntry &entry = *mVideoQueue.begin();
290
291 sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, id());
292 msg->setInt32("generation", mVideoQueueGeneration);
293
294 int64_t delayUs;
295
296 if (entry.mBuffer == NULL) {
297 // EOS doesn't carry a timestamp.
298 delayUs = 0;
299 } else {
300 int64_t mediaTimeUs;
301 CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
302
303 if (mAnchorTimeMediaUs < 0) {
304 delayUs = 0;
305
Andreas Huber3831a062010-12-21 10:22:33 -0800306 if (!mHasAudio) {
Andreas Huberf9334412010-12-15 15:17:42 -0800307 mAnchorTimeMediaUs = mediaTimeUs;
308 mAnchorTimeRealUs = ALooper::GetNowUs();
309 }
310 } else {
311 int64_t realTimeUs =
312 (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs;
313
314 delayUs = realTimeUs - ALooper::GetNowUs();
315 }
316 }
317
318 msg->post(delayUs);
319
320 mDrainVideoQueuePending = true;
321}
322
323void NuPlayer::Renderer::onDrainVideoQueue() {
324 if (mVideoQueue.empty()) {
325 return;
326 }
327
328 QueueEntry *entry = &*mVideoQueue.begin();
329
330 if (entry->mBuffer == NULL) {
331 // EOS
332
Andreas Huberc92fd242011-08-16 13:48:44 -0700333 notifyEOS(false /* audio */, entry->mFinalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800334
335 mVideoQueue.erase(mVideoQueue.begin());
336 entry = NULL;
337 return;
338 }
339
340#if 0
341 int64_t mediaTimeUs;
342 CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
343
344 LOGI("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
345#endif
346
347 entry->mNotifyConsumed->setInt32("render", true);
348 entry->mNotifyConsumed->post();
349 mVideoQueue.erase(mVideoQueue.begin());
350 entry = NULL;
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800351
352 notifyPosition();
Andreas Huberf9334412010-12-15 15:17:42 -0800353}
354
Andreas Huberc92fd242011-08-16 13:48:44 -0700355void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
Andreas Huberf9334412010-12-15 15:17:42 -0800356 sp<AMessage> notify = mNotify->dup();
357 notify->setInt32("what", kWhatEOS);
358 notify->setInt32("audio", static_cast<int32_t>(audio));
Andreas Huberc92fd242011-08-16 13:48:44 -0700359 notify->setInt32("finalResult", finalResult);
Andreas Huberf9334412010-12-15 15:17:42 -0800360 notify->post();
361}
362
363void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
364 int32_t audio;
365 CHECK(msg->findInt32("audio", &audio));
366
Andreas Huberbc7f5b22011-01-21 10:15:23 -0800367 if (audio) {
368 mHasAudio = true;
369 } else {
370 mHasVideo = true;
371 }
372
Andreas Huberf9334412010-12-15 15:17:42 -0800373 if (dropBufferWhileFlushing(audio, msg)) {
374 return;
375 }
376
377 sp<RefBase> obj;
378 CHECK(msg->findObject("buffer", &obj));
379 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
380
381 sp<AMessage> notifyConsumed;
382 CHECK(msg->findMessage("notifyConsumed", &notifyConsumed));
383
384 QueueEntry entry;
385 entry.mBuffer = buffer;
386 entry.mNotifyConsumed = notifyConsumed;
387 entry.mOffset = 0;
388 entry.mFinalResult = OK;
389
390 if (audio) {
391 mAudioQueue.push_back(entry);
392 postDrainAudioQueue();
393 } else {
394 mVideoQueue.push_back(entry);
395 postDrainVideoQueue();
396 }
397
398 if (mSyncQueues && !mAudioQueue.empty() && !mVideoQueue.empty()) {
399 int64_t firstAudioTimeUs;
400 int64_t firstVideoTimeUs;
401 CHECK((*mAudioQueue.begin()).mBuffer->meta()
402 ->findInt64("timeUs", &firstAudioTimeUs));
403 CHECK((*mVideoQueue.begin()).mBuffer->meta()
404 ->findInt64("timeUs", &firstVideoTimeUs));
405
406 int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
407
408 LOGV("queueDiff = %.2f secs", diff / 1E6);
409
410 if (diff > 100000ll) {
411 // Audio data starts More than 0.1 secs before video.
412 // Drop some audio.
413
414 (*mAudioQueue.begin()).mNotifyConsumed->post();
415 mAudioQueue.erase(mAudioQueue.begin());
416 return;
417 }
418
419 syncQueuesDone();
420 }
421}
422
423void NuPlayer::Renderer::syncQueuesDone() {
424 if (!mSyncQueues) {
425 return;
426 }
427
428 mSyncQueues = false;
429
430 if (!mAudioQueue.empty()) {
431 postDrainAudioQueue();
432 }
433
434 if (!mVideoQueue.empty()) {
435 postDrainVideoQueue();
436 }
437}
438
439void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) {
440 int32_t audio;
441 CHECK(msg->findInt32("audio", &audio));
442
443 if (dropBufferWhileFlushing(audio, msg)) {
444 return;
445 }
446
447 int32_t finalResult;
448 CHECK(msg->findInt32("finalResult", &finalResult));
449
450 QueueEntry entry;
451 entry.mOffset = 0;
452 entry.mFinalResult = finalResult;
453
454 if (audio) {
455 mAudioQueue.push_back(entry);
456 postDrainAudioQueue();
457 } else {
458 mVideoQueue.push_back(entry);
459 postDrainVideoQueue();
460 }
461}
462
463void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
464 int32_t audio;
465 CHECK(msg->findInt32("audio", &audio));
466
467 // If we're currently syncing the queues, i.e. dropping audio while
468 // aligning the first audio/video buffer times and only one of the
469 // two queues has data, we may starve that queue by not requesting
470 // more buffers from the decoder. If the other source then encounters
471 // a discontinuity that leads to flushing, we'll never find the
472 // corresponding discontinuity on the other queue.
473 // Therefore we'll stop syncing the queues if at least one of them
474 // is flushed.
475 syncQueuesDone();
476
477 if (audio) {
478 flushQueue(&mAudioQueue);
479
480 Mutex::Autolock autoLock(mFlushLock);
481 mFlushingAudio = false;
482
483 mDrainAudioQueuePending = false;
484 ++mAudioQueueGeneration;
485 } else {
486 flushQueue(&mVideoQueue);
487
488 Mutex::Autolock autoLock(mFlushLock);
489 mFlushingVideo = false;
490
491 mDrainVideoQueuePending = false;
492 ++mVideoQueueGeneration;
493 }
494
495 notifyFlushComplete(audio);
496}
497
498void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) {
499 while (!queue->empty()) {
500 QueueEntry *entry = &*queue->begin();
501
502 if (entry->mBuffer != NULL) {
503 entry->mNotifyConsumed->post();
504 }
505
506 queue->erase(queue->begin());
507 entry = NULL;
508 }
509}
510
511void NuPlayer::Renderer::notifyFlushComplete(bool audio) {
512 sp<AMessage> notify = mNotify->dup();
513 notify->setInt32("what", kWhatFlushComplete);
514 notify->setInt32("audio", static_cast<int32_t>(audio));
515 notify->post();
516}
517
518bool NuPlayer::Renderer::dropBufferWhileFlushing(
519 bool audio, const sp<AMessage> &msg) {
520 bool flushing = false;
521
522 {
523 Mutex::Autolock autoLock(mFlushLock);
524 if (audio) {
525 flushing = mFlushingAudio;
526 } else {
527 flushing = mFlushingVideo;
528 }
529 }
530
531 if (!flushing) {
532 return false;
533 }
534
535 sp<AMessage> notifyConsumed;
536 if (msg->findMessage("notifyConsumed", &notifyConsumed)) {
537 notifyConsumed->post();
538 }
539
540 return true;
541}
542
Andreas Huber3831a062010-12-21 10:22:33 -0800543void NuPlayer::Renderer::onAudioSinkChanged() {
544 CHECK(!mDrainAudioQueuePending);
545 mNumFramesWritten = 0;
546}
547
Andreas Huber43c3e6c2011-01-05 12:17:08 -0800548void NuPlayer::Renderer::notifyPosition() {
549 if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) {
550 return;
551 }
552
553 int64_t nowUs = ALooper::GetNowUs();
554 int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
555
556 sp<AMessage> notify = mNotify->dup();
557 notify->setInt32("what", kWhatPosition);
558 notify->setInt64("positionUs", positionUs);
559 notify->post();
560}
561
Andreas Huberb4082222011-01-20 15:23:04 -0800562void NuPlayer::Renderer::onPause() {
563 CHECK(!mPaused);
564
565 mDrainAudioQueuePending = false;
566 ++mAudioQueueGeneration;
567
568 mDrainVideoQueuePending = false;
569 ++mVideoQueueGeneration;
570
571 if (mHasAudio) {
572 mAudioSink->pause();
573 }
574
575 mPaused = true;
576}
577
578void NuPlayer::Renderer::onResume() {
579 CHECK(mPaused);
580
581 if (mHasAudio) {
582 mAudioSink->start();
583 }
584
585 mPaused = false;
586
587 if (!mAudioQueue.empty()) {
588 postDrainAudioQueue();
589 }
590
591 if (!mVideoQueue.empty()) {
592 postDrainVideoQueue();
593 }
594}
595
Andreas Huberf9334412010-12-15 15:17:42 -0800596} // namespace android
597