1 /*
2 * Copyright 2015 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 "MediaSync"
19 #include <inttypes.h>
20
21 #include <gui/BufferQueue.h>
22 #include <gui/IGraphicBufferConsumer.h>
23 #include <gui/IGraphicBufferProducer.h>
24
25 #include <media/AudioTrack.h>
26 #include <media/stagefright/MediaClock.h>
27 #include <media/stagefright/MediaSync.h>
28 #include <media/stagefright/VideoFrameScheduler.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/ALooper.h>
31 #include <media/stagefright/foundation/AMessage.h>
32
33 #include <ui/GraphicBuffer.h>
34
35 #include <system/window.h>
36
37 // Maximum late time allowed for a video frame to be rendered. When a video
38 // frame arrives later than this number, it will be discarded without rendering.
39 static const int64_t kMaxAllowedVideoLateTimeUs = 40000LL;
40
41 namespace android {
42
43 // static
create()44 sp<MediaSync> MediaSync::create() {
45 sp<MediaSync> sync = new MediaSync();
46 sync->mLooper->registerHandler(sync);
47 return sync;
48 }
49
MediaSync()50 MediaSync::MediaSync()
51 : mIsAbandoned(false),
52 mMutex(),
53 mReleaseCondition(),
54 mNumOutstandingBuffers(0),
55 mUsageFlagsFromOutput(0),
56 mMaxAcquiredBufferCount(1),
57 mReturnPendingInputFrame(false),
58 mNativeSampleRateInHz(0),
59 mNumFramesWritten(0),
60 mHasAudio(false),
61 mNextBufferItemMediaUs(-1),
62 mPlaybackRate(0.0) {
63 mMediaClock = new MediaClock;
64 mMediaClock->init();
65
66 // initialize settings
67 mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
68 mPlaybackSettings.mSpeed = mPlaybackRate;
69
70 mLooper = new ALooper;
71 mLooper->setName("MediaSync");
72 mLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
73 }
74
~MediaSync()75 MediaSync::~MediaSync() {
76 if (mInput != NULL) {
77 mInput->consumerDisconnect();
78 }
79 if (mOutput != NULL) {
80 mOutput->disconnect(NATIVE_WINDOW_API_MEDIA);
81 }
82
83 if (mLooper != NULL) {
84 mLooper->unregisterHandler(id());
85 mLooper->stop();
86 }
87 }
88
setSurface(const sp<IGraphicBufferProducer> & output)89 status_t MediaSync::setSurface(const sp<IGraphicBufferProducer> &output) {
90 Mutex::Autolock lock(mMutex);
91
92 if (output == mOutput) {
93 return NO_ERROR; // same output surface.
94 }
95
96 if (output == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_VSYNC) {
97 ALOGE("setSurface: output surface is used as sync source and cannot be removed.");
98 return INVALID_OPERATION;
99 }
100
101 if (output != NULL) {
102 int newUsage = 0;
103 output->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &newUsage);
104
105 // Check usage flags only when current output surface has been used to create input surface.
106 if (mOutput != NULL && mInput != NULL) {
107 int ignoredFlags = (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER
108 | GRALLOC_USAGE_EXTERNAL_DISP);
109 // New output surface is not allowed to add new usage flag except ignored ones.
110 if ((newUsage & ~(mUsageFlagsFromOutput | ignoredFlags)) != 0) {
111 ALOGE("setSurface: new output surface has new usage flag not used by current one.");
112 return BAD_VALUE;
113 }
114 }
115
116 // Try to connect to new output surface. If failed, current output surface will not
117 // be changed.
118 IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
119 sp<OutputListener> listener(new OutputListener(this, output));
120 IInterface::asBinder(output)->linkToDeath(listener);
121 status_t status =
122 output->connect(listener,
123 NATIVE_WINDOW_API_MEDIA,
124 true /* producerControlledByApp */,
125 &queueBufferOutput);
126 if (status != NO_ERROR) {
127 ALOGE("setSurface: failed to connect (%d)", status);
128 return status;
129 }
130
131 if (mFrameScheduler == NULL) {
132 mFrameScheduler = new VideoFrameScheduler();
133 mFrameScheduler->init();
134 }
135 }
136
137 if (mOutput != NULL) {
138 mOutput->disconnect(NATIVE_WINDOW_API_MEDIA);
139 while (!mBuffersSentToOutput.isEmpty()) {
140 returnBufferToInput_l(mBuffersSentToOutput.valueAt(0), Fence::NO_FENCE);
141 mBuffersSentToOutput.removeItemsAt(0);
142 }
143 }
144
145 mOutput = output;
146
147 return NO_ERROR;
148 }
149
150 // |audioTrack| is used only for querying information.
setAudioTrack(const sp<AudioTrack> & audioTrack)151 status_t MediaSync::setAudioTrack(const sp<AudioTrack> &audioTrack) {
152 Mutex::Autolock lock(mMutex);
153
154 // TODO: support audio track change.
155 if (mAudioTrack != NULL) {
156 ALOGE("setAudioTrack: audioTrack has already been configured.");
157 return INVALID_OPERATION;
158 }
159
160 if (audioTrack == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_AUDIO) {
161 ALOGE("setAudioTrack: audioTrack is used as sync source and cannot be removed.");
162 return INVALID_OPERATION;
163 }
164
165 if (audioTrack != NULL) {
166 // check if audio track supports the playback settings
167 if (mPlaybackSettings.mSpeed != 0.f
168 && audioTrack->setPlaybackRate(mPlaybackSettings) != OK) {
169 ALOGE("playback settings are not supported by the audio track");
170 return INVALID_OPERATION;
171 }
172 uint32_t nativeSampleRateInHz = audioTrack->getOriginalSampleRate();
173 if (nativeSampleRateInHz <= 0) {
174 ALOGE("setAudioTrack: native sample rate should be positive.");
175 return BAD_VALUE;
176 }
177 mAudioTrack = audioTrack;
178 mNativeSampleRateInHz = nativeSampleRateInHz;
179 (void)setPlaybackSettings_l(mPlaybackSettings);
180 }
181 else {
182 mAudioTrack = NULL;
183 mNativeSampleRateInHz = 0;
184 }
185
186 // potentially resync to new source
187 resync_l();
188 return OK;
189 }
190
createInputSurface(sp<IGraphicBufferProducer> * outBufferProducer)191 status_t MediaSync::createInputSurface(
192 sp<IGraphicBufferProducer> *outBufferProducer) {
193 if (outBufferProducer == NULL) {
194 return BAD_VALUE;
195 }
196
197 Mutex::Autolock lock(mMutex);
198
199 if (mOutput == NULL) {
200 return NO_INIT;
201 }
202
203 if (mInput != NULL) {
204 return INVALID_OPERATION;
205 }
206
207 sp<IGraphicBufferProducer> bufferProducer;
208 sp<IGraphicBufferConsumer> bufferConsumer;
209 BufferQueue::createBufferQueue(&bufferProducer, &bufferConsumer);
210
211 sp<InputListener> listener(new InputListener(this));
212 IInterface::asBinder(bufferConsumer)->linkToDeath(listener);
213 status_t status =
214 bufferConsumer->consumerConnect(listener, false /* controlledByApp */);
215 if (status == NO_ERROR) {
216 bufferConsumer->setConsumerName(String8("MediaSync"));
217 // propagate usage bits from output surface
218 mUsageFlagsFromOutput = 0;
219 mOutput->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &mUsageFlagsFromOutput);
220 bufferConsumer->setConsumerUsageBits(mUsageFlagsFromOutput);
221 *outBufferProducer = bufferProducer;
222 mInput = bufferConsumer;
223
224 // set undequeued buffer count
225 int minUndequeuedBuffers;
226 mOutput->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
227 mMaxAcquiredBufferCount = minUndequeuedBuffers;
228 bufferConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount);
229 }
230 return status;
231 }
232
resync_l()233 void MediaSync::resync_l() {
234 AVSyncSource src = mSyncSettings.mSource;
235 if (src == AVSYNC_SOURCE_DEFAULT) {
236 if (mAudioTrack != NULL) {
237 src = AVSYNC_SOURCE_AUDIO;
238 } else {
239 src = AVSYNC_SOURCE_SYSTEM_CLOCK;
240 }
241 }
242
243 // TODO: resync ourselves to the current clock (e.g. on sync source change)
244 updatePlaybackRate_l(mPlaybackRate);
245 }
246
updatePlaybackRate_l(float rate)247 void MediaSync::updatePlaybackRate_l(float rate) {
248 if (rate > mPlaybackRate) {
249 mNextBufferItemMediaUs = -1;
250 }
251 mPlaybackRate = rate;
252 // TODO: update frame scheduler with this info
253 mMediaClock->setPlaybackRate(rate);
254 onDrainVideo_l();
255 }
256
getMediaClock()257 sp<const MediaClock> MediaSync::getMediaClock() {
258 return mMediaClock;
259 }
260
getPlayTimeForPendingAudioFrames(int64_t * outTimeUs)261 status_t MediaSync::getPlayTimeForPendingAudioFrames(int64_t *outTimeUs) {
262 Mutex::Autolock lock(mMutex);
263 // User should check the playback rate if it doesn't want to receive a
264 // huge number for play time.
265 if (mPlaybackRate == 0.0f) {
266 *outTimeUs = INT64_MAX;
267 return OK;
268 }
269
270 uint32_t numFramesPlayed = 0;
271 if (mAudioTrack != NULL) {
272 status_t res = mAudioTrack->getPosition(&numFramesPlayed);
273 if (res != OK) {
274 return res;
275 }
276 }
277
278 int64_t numPendingFrames = mNumFramesWritten - numFramesPlayed;
279 if (numPendingFrames < 0) {
280 numPendingFrames = 0;
281 ALOGW("getPlayTimeForPendingAudioFrames: pending frame count is negative.");
282 }
283 double timeUs = numPendingFrames * 1000000.0
284 / (mNativeSampleRateInHz * (double)mPlaybackRate);
285 if (timeUs > (double)INT64_MAX) {
286 // Overflow.
287 *outTimeUs = INT64_MAX;
288 ALOGW("getPlayTimeForPendingAudioFrames: play time for pending audio frames "
289 "is too high, possibly due to super low playback rate(%f)", mPlaybackRate);
290 } else {
291 *outTimeUs = (int64_t)timeUs;
292 }
293
294 return OK;
295 }
296
updateQueuedAudioData(size_t sizeInBytes,int64_t presentationTimeUs)297 status_t MediaSync::updateQueuedAudioData(
298 size_t sizeInBytes, int64_t presentationTimeUs) {
299 if (sizeInBytes == 0) {
300 return OK;
301 }
302
303 Mutex::Autolock lock(mMutex);
304
305 if (mAudioTrack == NULL) {
306 ALOGW("updateQueuedAudioData: audioTrack has NOT been configured.");
307 return INVALID_OPERATION;
308 }
309
310 int64_t numFrames = sizeInBytes / mAudioTrack->frameSize();
311 int64_t maxMediaTimeUs = presentationTimeUs
312 + getDurationIfPlayedAtNativeSampleRate_l(numFrames);
313
314 int64_t nowUs = ALooper::GetNowUs();
315 int64_t nowMediaUs = presentationTimeUs
316 - getDurationIfPlayedAtNativeSampleRate_l(mNumFramesWritten)
317 + getPlayedOutAudioDurationMedia_l(nowUs);
318
319 mNumFramesWritten += numFrames;
320
321 int64_t oldRealTime = -1;
322 if (mNextBufferItemMediaUs != -1) {
323 oldRealTime = getRealTime(mNextBufferItemMediaUs, nowUs);
324 }
325
326 mMediaClock->updateAnchor(nowMediaUs, nowUs, maxMediaTimeUs);
327 mHasAudio = true;
328
329 if (oldRealTime != -1) {
330 int64_t newRealTime = getRealTime(mNextBufferItemMediaUs, nowUs);
331 if (newRealTime >= oldRealTime) {
332 return OK;
333 }
334 }
335
336 mNextBufferItemMediaUs = -1;
337 onDrainVideo_l();
338 return OK;
339 }
340
setName(const AString & name)341 void MediaSync::setName(const AString &name) {
342 Mutex::Autolock lock(mMutex);
343 mInput->setConsumerName(String8(name.c_str()));
344 }
345
flush()346 void MediaSync::flush() {
347 Mutex::Autolock lock(mMutex);
348 if (mFrameScheduler != NULL) {
349 mFrameScheduler->restart();
350 }
351 while (!mBufferItems.empty()) {
352 BufferItem *bufferItem = &*mBufferItems.begin();
353 returnBufferToInput_l(bufferItem->mGraphicBuffer, bufferItem->mFence);
354 mBufferItems.erase(mBufferItems.begin());
355 }
356 mNextBufferItemMediaUs = -1;
357 mNumFramesWritten = 0;
358 mReturnPendingInputFrame = true;
359 mReleaseCondition.signal();
360 mMediaClock->clearAnchor();
361 }
362
setVideoFrameRateHint(float rate)363 status_t MediaSync::setVideoFrameRateHint(float rate) {
364 Mutex::Autolock lock(mMutex);
365 if (rate < 0.f) {
366 return BAD_VALUE;
367 }
368 if (mFrameScheduler != NULL) {
369 mFrameScheduler->init(rate);
370 }
371 return OK;
372 }
373
getVideoFrameRate()374 float MediaSync::getVideoFrameRate() {
375 Mutex::Autolock lock(mMutex);
376 if (mFrameScheduler != NULL) {
377 float fps = mFrameScheduler->getFrameRate();
378 if (fps > 0.f) {
379 return fps;
380 }
381 }
382
383 // we don't have or know the frame rate
384 return -1.f;
385 }
386
setSyncSettings(const AVSyncSettings & syncSettings)387 status_t MediaSync::setSyncSettings(const AVSyncSettings &syncSettings) {
388 // validate settings
389 if (syncSettings.mSource >= AVSYNC_SOURCE_MAX
390 || syncSettings.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
391 || syncSettings.mTolerance < 0.f
392 || syncSettings.mTolerance >= AVSYNC_TOLERANCE_MAX) {
393 return BAD_VALUE;
394 }
395
396 Mutex::Autolock lock(mMutex);
397
398 // verify that we have the sync source
399 switch (syncSettings.mSource) {
400 case AVSYNC_SOURCE_AUDIO:
401 if (mAudioTrack == NULL) {
402 ALOGE("setSyncSettings: audio sync source requires an audio track");
403 return BAD_VALUE;
404 }
405 break;
406 case AVSYNC_SOURCE_VSYNC:
407 if (mOutput == NULL) {
408 ALOGE("setSyncSettings: vsync sync source requires an output surface");
409 return BAD_VALUE;
410 }
411 break;
412 default:
413 break;
414 }
415
416 mSyncSettings = syncSettings;
417 resync_l();
418 return OK;
419 }
420
getSyncSettings(AVSyncSettings * syncSettings)421 void MediaSync::getSyncSettings(AVSyncSettings *syncSettings) {
422 Mutex::Autolock lock(mMutex);
423 *syncSettings = mSyncSettings;
424 }
425
setPlaybackSettings(const AudioPlaybackRate & rate)426 status_t MediaSync::setPlaybackSettings(const AudioPlaybackRate &rate) {
427 Mutex::Autolock lock(mMutex);
428
429 status_t err = setPlaybackSettings_l(rate);
430 if (err == OK) {
431 // TODO: adjust rate if using VSYNC as source
432 updatePlaybackRate_l(rate.mSpeed);
433 }
434 return err;
435 }
436
setPlaybackSettings_l(const AudioPlaybackRate & rate)437 status_t MediaSync::setPlaybackSettings_l(const AudioPlaybackRate &rate) {
438 if (rate.mSpeed < 0.f || rate.mPitch < 0.f) {
439 // We don't validate other audio settings.
440 // They will be validated when/if audiotrack is set.
441 return BAD_VALUE;
442 }
443
444 if (mAudioTrack != NULL) {
445 if (rate.mSpeed == 0.f) {
446 mAudioTrack->pause();
447 } else {
448 status_t err = mAudioTrack->setPlaybackRate(rate);
449 if (err != OK) {
450 return BAD_VALUE;
451 }
452
453 // ignore errors
454 (void)mAudioTrack->start();
455 }
456 }
457 mPlaybackSettings = rate;
458 return OK;
459 }
460
getPlaybackSettings(AudioPlaybackRate * rate)461 void MediaSync::getPlaybackSettings(AudioPlaybackRate *rate) {
462 Mutex::Autolock lock(mMutex);
463 *rate = mPlaybackSettings;
464 }
465
getRealTime(int64_t mediaTimeUs,int64_t nowUs)466 int64_t MediaSync::getRealTime(int64_t mediaTimeUs, int64_t nowUs) {
467 int64_t realUs;
468 if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
469 // If failed to get current position, e.g. due to audio clock is
470 // not ready, then just play out video immediately without delay.
471 return nowUs;
472 }
473 return realUs;
474 }
475
getDurationIfPlayedAtNativeSampleRate_l(int64_t numFrames)476 int64_t MediaSync::getDurationIfPlayedAtNativeSampleRate_l(int64_t numFrames) {
477 return (numFrames * 1000000LL / mNativeSampleRateInHz);
478 }
479
getPlayedOutAudioDurationMedia_l(int64_t nowUs)480 int64_t MediaSync::getPlayedOutAudioDurationMedia_l(int64_t nowUs) {
481 CHECK(mAudioTrack != NULL);
482
483 uint32_t numFramesPlayed;
484 int64_t numFramesPlayedAtUs;
485 AudioTimestamp ts;
486
487 status_t res = mAudioTrack->getTimestamp(ts);
488 if (res == OK) {
489 // case 1: mixing audio tracks.
490 numFramesPlayed = ts.mPosition;
491 numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
492 //ALOGD("getTimestamp: OK %d %lld",
493 // numFramesPlayed, (long long)numFramesPlayedAtUs);
494 } else if (res == WOULD_BLOCK) {
495 // case 2: transitory state on start of a new track
496 numFramesPlayed = 0;
497 numFramesPlayedAtUs = nowUs;
498 //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
499 // numFramesPlayed, (long long)numFramesPlayedAtUs);
500 } else {
501 // case 3: transitory at new track or audio fast tracks.
502 res = mAudioTrack->getPosition(&numFramesPlayed);
503 CHECK_EQ(res, (status_t)OK);
504 numFramesPlayedAtUs = nowUs;
505 numFramesPlayedAtUs += 1000LL * mAudioTrack->latency() / 2; /* XXX */
506 //ALOGD("getPosition: %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
507 }
508
509 //can't be negative until 12.4 hrs, test.
510 //CHECK_EQ(numFramesPlayed & (1 << 31), 0);
511 int64_t durationUs =
512 getDurationIfPlayedAtNativeSampleRate_l(numFramesPlayed)
513 + nowUs - numFramesPlayedAtUs;
514 if (durationUs < 0) {
515 // Occurs when numFramesPlayed position is very small and the following:
516 // (1) In case 1, the time nowUs is computed before getTimestamp() is
517 // called and numFramesPlayedAtUs is greater than nowUs by time more
518 // than numFramesPlayed.
519 // (2) In case 3, using getPosition and adding mAudioTrack->latency()
520 // to numFramesPlayedAtUs, by a time amount greater than
521 // numFramesPlayed.
522 //
523 // Both of these are transitory conditions.
524 ALOGV("getPlayedOutAudioDurationMedia_l: negative duration %lld "
525 "set to zero", (long long)durationUs);
526 durationUs = 0;
527 }
528 ALOGV("getPlayedOutAudioDurationMedia_l(%lld) nowUs(%lld) frames(%u) "
529 "framesAt(%lld)",
530 (long long)durationUs, (long long)nowUs, numFramesPlayed,
531 (long long)numFramesPlayedAtUs);
532 return durationUs;
533 }
534
onDrainVideo_l()535 void MediaSync::onDrainVideo_l() {
536 if (!isPlaying()) {
537 return;
538 }
539
540 while (!mBufferItems.empty()) {
541 int64_t nowUs = ALooper::GetNowUs();
542 BufferItem *bufferItem = &*mBufferItems.begin();
543 int64_t itemMediaUs = bufferItem->mTimestamp / 1000;
544 int64_t itemRealUs = getRealTime(itemMediaUs, nowUs);
545
546 // adjust video frame PTS based on vsync
547 itemRealUs = mFrameScheduler->schedule(itemRealUs * 1000) / 1000;
548 int64_t twoVsyncsUs = 2 * (mFrameScheduler->getVsyncPeriod() / 1000);
549
550 // post 2 display refreshes before rendering is due
551 if (itemRealUs <= nowUs + twoVsyncsUs) {
552 ALOGV("adjusting PTS from %lld to %lld",
553 (long long)bufferItem->mTimestamp / 1000, (long long)itemRealUs);
554 bufferItem->mTimestamp = itemRealUs * 1000;
555 bufferItem->mIsAutoTimestamp = false;
556
557 if (mHasAudio) {
558 if (nowUs - itemRealUs <= kMaxAllowedVideoLateTimeUs) {
559 renderOneBufferItem_l(*bufferItem);
560 } else {
561 // too late.
562 returnBufferToInput_l(
563 bufferItem->mGraphicBuffer, bufferItem->mFence);
564 mFrameScheduler->restart();
565 }
566 } else {
567 // always render video buffer in video-only mode.
568 renderOneBufferItem_l(*bufferItem);
569
570 // smooth out videos >= 10fps
571 mMediaClock->updateAnchor(
572 itemMediaUs, nowUs, itemMediaUs + 100000);
573 }
574
575 mBufferItems.erase(mBufferItems.begin());
576 mNextBufferItemMediaUs = -1;
577 } else {
578 if (mNextBufferItemMediaUs == -1
579 || mNextBufferItemMediaUs > itemMediaUs) {
580 sp<AMessage> msg = new AMessage(kWhatDrainVideo, this);
581 msg->post(itemRealUs - nowUs - twoVsyncsUs);
582 mNextBufferItemMediaUs = itemMediaUs;
583 }
584 break;
585 }
586 }
587 }
588
onFrameAvailableFromInput()589 void MediaSync::onFrameAvailableFromInput() {
590 Mutex::Autolock lock(mMutex);
591
592 const static nsecs_t kAcquireWaitTimeout = 2000000000; // 2 seconds
593
594 mReturnPendingInputFrame = false;
595
596 // If there are too many outstanding buffers, wait until a buffer is
597 // released back to the input in onBufferReleased.
598 // NOTE: BufferQueue allows dequeuing maxAcquiredBufferCount + 1 buffers
599 while (mNumOutstandingBuffers > mMaxAcquiredBufferCount
600 && !mIsAbandoned && !mReturnPendingInputFrame) {
601 if (mReleaseCondition.waitRelative(mMutex, kAcquireWaitTimeout) != OK) {
602 ALOGI_IF(mPlaybackRate != 0.f, "still waiting to release a buffer before acquire");
603 }
604
605 // If the sync is abandoned while we are waiting, the release
606 // condition variable will be broadcast, and we should just return
607 // without attempting to do anything more (since the input queue will
608 // also be abandoned).
609 if (mIsAbandoned) {
610 return;
611 }
612 }
613
614 // Acquire and detach the buffer from the input.
615 BufferItem bufferItem;
616 status_t status = mInput->acquireBuffer(&bufferItem, 0 /* presentWhen */);
617 if (status != NO_ERROR) {
618 ALOGE("acquiring buffer from input failed (%d)", status);
619 return;
620 }
621 ++mNumOutstandingBuffers;
622
623 ALOGV("acquired buffer %#llx from input", (long long)bufferItem.mGraphicBuffer->getId());
624
625 status = mInput->detachBuffer(bufferItem.mSlot);
626 if (status != NO_ERROR) {
627 ALOGE("detaching buffer from input failed (%d)", status);
628 if (status == NO_INIT) {
629 // If the input has been abandoned, move on.
630 onAbandoned_l(true /* isInput */);
631 }
632 return;
633 }
634
635 if (mBuffersFromInput.indexOfKey(bufferItem.mGraphicBuffer->getId()) >= 0) {
636 // Something is wrong since this buffer should be at our hands, bail.
637 ALOGE("received buffer multiple times from input");
638 mInput->consumerDisconnect();
639 onAbandoned_l(true /* isInput */);
640 return;
641 }
642 mBuffersFromInput.add(bufferItem.mGraphicBuffer->getId(), bufferItem.mGraphicBuffer);
643
644 // If flush happened while waiting for a buffer to be released, simply return it
645 // TRICKY: do it here after it is detached so that we don't have to cache mGraphicBuffer.
646 if (mReturnPendingInputFrame) {
647 mReturnPendingInputFrame = false;
648 returnBufferToInput_l(bufferItem.mGraphicBuffer, bufferItem.mFence);
649 return;
650 }
651
652 mBufferItems.push_back(bufferItem);
653
654 if (mBufferItems.size() == 1) {
655 onDrainVideo_l();
656 }
657 }
658
renderOneBufferItem_l(const BufferItem & bufferItem)659 void MediaSync::renderOneBufferItem_l(const BufferItem &bufferItem) {
660 IGraphicBufferProducer::QueueBufferInput queueInput(
661 bufferItem.mTimestamp,
662 bufferItem.mIsAutoTimestamp,
663 bufferItem.mDataSpace,
664 bufferItem.mCrop,
665 static_cast<int32_t>(bufferItem.mScalingMode),
666 bufferItem.mTransform,
667 bufferItem.mFence);
668
669 // Attach and queue the buffer to the output.
670 int slot;
671 mOutput->setGenerationNumber(bufferItem.mGraphicBuffer->getGenerationNumber());
672 status_t status = mOutput->attachBuffer(&slot, bufferItem.mGraphicBuffer);
673 ALOGE_IF(status != NO_ERROR, "attaching buffer to output failed (%d)", status);
674 if (status == NO_ERROR) {
675 IGraphicBufferProducer::QueueBufferOutput queueOutput;
676 status = mOutput->queueBuffer(slot, queueInput, &queueOutput);
677 ALOGE_IF(status != NO_ERROR, "queueing buffer to output failed (%d)", status);
678 }
679
680 if (status != NO_ERROR) {
681 returnBufferToInput_l(bufferItem.mGraphicBuffer, bufferItem.mFence);
682 if (status == NO_INIT) {
683 // If the output has been abandoned, move on.
684 onAbandoned_l(false /* isInput */);
685 }
686 return;
687 }
688
689 if (mBuffersSentToOutput.indexOfKey(bufferItem.mGraphicBuffer->getId()) >= 0) {
690 // Something is wrong since this buffer should be held by output now, bail.
691 mInput->consumerDisconnect();
692 onAbandoned_l(true /* isInput */);
693 return;
694 }
695 mBuffersSentToOutput.add(bufferItem.mGraphicBuffer->getId(), bufferItem.mGraphicBuffer);
696
697 ALOGV("queued buffer %#llx to output", (long long)bufferItem.mGraphicBuffer->getId());
698 }
699
onBufferReleasedByOutput(sp<IGraphicBufferProducer> & output)700 void MediaSync::onBufferReleasedByOutput(sp<IGraphicBufferProducer> &output) {
701 Mutex::Autolock lock(mMutex);
702
703 if (output != mOutput) {
704 return; // This is not the current output, ignore.
705 }
706
707 sp<GraphicBuffer> buffer;
708 sp<Fence> fence;
709 status_t status = mOutput->detachNextBuffer(&buffer, &fence);
710 ALOGE_IF(status != NO_ERROR, "detaching buffer from output failed (%d)", status);
711
712 if (status == NO_INIT) {
713 // If the output has been abandoned, we can't do anything else,
714 // since buffer is invalid.
715 onAbandoned_l(false /* isInput */);
716 return;
717 }
718
719 ALOGV("detached buffer %#llx from output", (long long)buffer->getId());
720
721 // If we've been abandoned, we can't return the buffer to the input, so just
722 // move on.
723 if (mIsAbandoned) {
724 return;
725 }
726
727 ssize_t ix = mBuffersSentToOutput.indexOfKey(buffer->getId());
728 if (ix < 0) {
729 // The buffer is unknown, maybe leftover, ignore.
730 return;
731 }
732 mBuffersSentToOutput.removeItemsAt(ix);
733
734 returnBufferToInput_l(buffer, fence);
735 }
736
returnBufferToInput_l(const sp<GraphicBuffer> & buffer,const sp<Fence> & fence)737 void MediaSync::returnBufferToInput_l(
738 const sp<GraphicBuffer> &buffer, const sp<Fence> &fence) {
739 ssize_t ix = mBuffersFromInput.indexOfKey(buffer->getId());
740 if (ix < 0) {
741 // The buffer is unknown, something is wrong, bail.
742 ALOGE("output returned unknown buffer");
743 mOutput->disconnect(NATIVE_WINDOW_API_MEDIA);
744 onAbandoned_l(false /* isInput */);
745 return;
746 }
747 sp<GraphicBuffer> oldBuffer = mBuffersFromInput.valueAt(ix);
748 mBuffersFromInput.removeItemsAt(ix);
749
750 // Attach and release the buffer back to the input.
751 int consumerSlot;
752 status_t status = mInput->attachBuffer(&consumerSlot, oldBuffer);
753 ALOGE_IF(status != NO_ERROR, "attaching buffer to input failed (%d)", status);
754 if (status == NO_ERROR) {
755 status = mInput->releaseBuffer(consumerSlot, 0 /* frameNumber */,
756 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
757 ALOGE_IF(status != NO_ERROR, "releasing buffer to input failed (%d)", status);
758 }
759
760 // Notify any waiting onFrameAvailable calls.
761 --mNumOutstandingBuffers;
762 mReleaseCondition.signal();
763
764 if (status == NO_ERROR) {
765 ALOGV("released buffer %#llx to input", (long long)oldBuffer->getId());
766 }
767 }
768
onAbandoned_l(bool isInput)769 void MediaSync::onAbandoned_l(bool isInput) {
770 ALOGE("the %s has abandoned me", (isInput ? "input" : "output"));
771 if (!mIsAbandoned) {
772 if (isInput) {
773 mOutput->disconnect(NATIVE_WINDOW_API_MEDIA);
774 } else {
775 mInput->consumerDisconnect();
776 }
777 mIsAbandoned = true;
778 }
779 mReleaseCondition.broadcast();
780 }
781
onMessageReceived(const sp<AMessage> & msg)782 void MediaSync::onMessageReceived(const sp<AMessage> &msg) {
783 switch (msg->what()) {
784 case kWhatDrainVideo:
785 {
786 Mutex::Autolock lock(mMutex);
787 if (mNextBufferItemMediaUs != -1) {
788 int64_t nowUs = ALooper::GetNowUs();
789 int64_t itemRealUs = getRealTime(mNextBufferItemMediaUs, nowUs);
790
791 // The message could arrive earlier than expected due to
792 // various reasons, e.g., media clock has been changed because
793 // of new anchor time or playback rate. In such cases, the
794 // message needs to be re-posted.
795 if (itemRealUs > nowUs) {
796 msg->post(itemRealUs - nowUs);
797 break;
798 }
799 }
800
801 onDrainVideo_l();
802 break;
803 }
804
805 default:
806 TRESPASS();
807 break;
808 }
809 }
810
InputListener(const sp<MediaSync> & sync)811 MediaSync::InputListener::InputListener(const sp<MediaSync> &sync)
812 : mSync(sync) {}
813
~InputListener()814 MediaSync::InputListener::~InputListener() {}
815
onFrameAvailable(const BufferItem &)816 void MediaSync::InputListener::onFrameAvailable(const BufferItem &/* item */) {
817 mSync->onFrameAvailableFromInput();
818 }
819
820 // We don't care about sideband streams, since we won't relay them.
onSidebandStreamChanged()821 void MediaSync::InputListener::onSidebandStreamChanged() {
822 ALOGE("onSidebandStreamChanged: got sideband stream unexpectedly.");
823 }
824
825
binderDied(const wp<IBinder> &)826 void MediaSync::InputListener::binderDied(const wp<IBinder> &/* who */) {
827 Mutex::Autolock lock(mSync->mMutex);
828 mSync->onAbandoned_l(true /* isInput */);
829 }
830
OutputListener(const sp<MediaSync> & sync,const sp<IGraphicBufferProducer> & output)831 MediaSync::OutputListener::OutputListener(const sp<MediaSync> &sync,
832 const sp<IGraphicBufferProducer> &output)
833 : mSync(sync),
834 mOutput(output) {}
835
~OutputListener()836 MediaSync::OutputListener::~OutputListener() {}
837
onBufferReleased()838 void MediaSync::OutputListener::onBufferReleased() {
839 mSync->onBufferReleasedByOutput(mOutput);
840 }
841
binderDied(const wp<IBinder> &)842 void MediaSync::OutputListener::binderDied(const wp<IBinder> &/* who */) {
843 Mutex::Autolock lock(mSync->mMutex);
844 mSync->onAbandoned_l(false /* isInput */);
845 }
846
847 } // namespace android
848