blob: 62d7c1a8d78537bb4598295687d3d99d4f63fe81 [file] [log] [blame]
James Dongc9dedc42011-05-01 12:36:22 -07001/*
2 * Copyright (C) 2011 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#undef DEBUG_HDCP
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "PreviewPlayerBase"
21#include <utils/Log.h>
22
23#include <dlfcn.h>
24
James Dongc9dedc42011-05-01 12:36:22 -070025#include "PreviewPlayerBase.h"
26#include "AudioPlayerBase.h"
27#include "include/SoftwareRenderer.h"
28#include "include/NuCachedSource2.h"
29#include "include/ThrottledSource.h"
30#include "include/MPEG2TSExtractor.h"
31
32#include <binder/IPCThreadState.h>
33#include <binder/IServiceManager.h>
34#include <media/IMediaPlayerService.h>
35#include <media/stagefright/foundation/hexdump.h>
36#include <media/stagefright/foundation/ADebug.h>
37#include <media/stagefright/DataSource.h>
38#include <media/stagefright/FileSource.h>
39#include <media/stagefright/MediaBuffer.h>
40#include <media/stagefright/MediaDefs.h>
41#include <media/stagefright/MediaExtractor.h>
42#include <media/stagefright/MediaSource.h>
43#include <media/stagefright/MetaData.h>
44#include <media/stagefright/OMXCodec.h>
45
46#include <surfaceflinger/Surface.h>
47#include <gui/ISurfaceTexture.h>
48#include <gui/SurfaceTextureClient.h>
49#include <surfaceflinger/ISurfaceComposer.h>
50
James Dongc9dedc42011-05-01 12:36:22 -070051#include <cutils/properties.h>
52
53#define USE_SURFACE_ALLOC 1
54
55namespace android {
56
57static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
58static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
James Dongc9dedc42011-05-01 12:36:22 -070059static const size_t kLowWaterMarkBytes = 40000;
60static const size_t kHighWaterMarkBytes = 200000;
61
62struct AwesomeEvent : public TimedEventQueue::Event {
63 AwesomeEvent(
64 PreviewPlayerBase *player,
65 void (PreviewPlayerBase::*method)())
66 : mPlayer(player),
67 mMethod(method) {
68 }
69
70protected:
71 virtual ~AwesomeEvent() {}
72
73 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
74 (mPlayer->*mMethod)();
75 }
76
77private:
78 PreviewPlayerBase *mPlayer;
79 void (PreviewPlayerBase::*mMethod)();
80
81 AwesomeEvent(const AwesomeEvent &);
82 AwesomeEvent &operator=(const AwesomeEvent &);
83};
84
85struct AwesomeLocalRenderer : public AwesomeRenderer {
86 AwesomeLocalRenderer(
87 const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
88 : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
89 }
90
91 virtual void render(MediaBuffer *buffer) {
92 render((const uint8_t *)buffer->data() + buffer->range_offset(),
93 buffer->range_length());
94 }
95
96 void render(const void *data, size_t size) {
97 mTarget->render(data, size, NULL);
98 }
99
100protected:
101 virtual ~AwesomeLocalRenderer() {
102 delete mTarget;
103 mTarget = NULL;
104 }
105
106private:
107 SoftwareRenderer *mTarget;
108
109 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
110 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
111};
112
113struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
114 AwesomeNativeWindowRenderer(
115 const sp<ANativeWindow> &nativeWindow,
116 int32_t rotationDegrees)
117 : mNativeWindow(nativeWindow) {
118 applyRotation(rotationDegrees);
119 }
120
121 virtual void render(MediaBuffer *buffer) {
122 status_t err = mNativeWindow->queueBuffer(
123 mNativeWindow.get(), buffer->graphicBuffer().get());
124 if (err != 0) {
125 LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
126 -err);
127 return;
128 }
129
130 sp<MetaData> metaData = buffer->meta_data();
131 metaData->setInt32(kKeyRendered, 1);
132 }
133
134protected:
135 virtual ~AwesomeNativeWindowRenderer() {}
136
137private:
138 sp<ANativeWindow> mNativeWindow;
139
140 void applyRotation(int32_t rotationDegrees) {
141 uint32_t transform;
142 switch (rotationDegrees) {
143 case 0: transform = 0; break;
144 case 90: transform = HAL_TRANSFORM_ROT_90; break;
145 case 180: transform = HAL_TRANSFORM_ROT_180; break;
146 case 270: transform = HAL_TRANSFORM_ROT_270; break;
147 default: transform = 0; break;
148 }
149
150 if (transform) {
151 CHECK_EQ(0, native_window_set_buffers_transform(
152 mNativeWindow.get(), transform));
153 }
154 }
155
156 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
157 AwesomeNativeWindowRenderer &operator=(
158 const AwesomeNativeWindowRenderer &);
159};
160
161// To collect the decoder usage
162void addBatteryData(uint32_t params) {
163 sp<IBinder> binder =
164 defaultServiceManager()->getService(String16("media.player"));
165 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
166 CHECK(service.get() != NULL);
167
168 service->addBatteryData(params);
169}
170
171////////////////////////////////////////////////////////////////////////////////
172PreviewPlayerBase::PreviewPlayerBase()
173 : mQueueStarted(false),
174 mTimeSource(NULL),
175 mVideoRendererIsPreview(false),
176 mAudioPlayer(NULL),
177 mDisplayWidth(0),
178 mDisplayHeight(0),
179 mFlags(0),
180 mExtractorFlags(0),
181 mVideoBuffer(NULL),
182 mDecryptHandle(NULL),
183 mLastVideoTimeUs(-1) {
184 CHECK_EQ(mClient.connect(), (status_t)OK);
185
186 DataSource::RegisterDefaultSniffers();
187
188 mVideoEvent = new AwesomeEvent(this, &PreviewPlayerBase::onVideoEvent);
189 mVideoEventPending = false;
190 mStreamDoneEvent = new AwesomeEvent(this, &PreviewPlayerBase::onStreamDone);
191 mStreamDoneEventPending = false;
192 mBufferingEvent = new AwesomeEvent(this, &PreviewPlayerBase::onBufferingUpdate);
193 mBufferingEventPending = false;
194 mVideoLagEvent = new AwesomeEvent(this, &PreviewPlayerBase::onVideoLagUpdate);
195 mVideoEventPending = false;
196
197 mCheckAudioStatusEvent = new AwesomeEvent(
198 this, &PreviewPlayerBase::onCheckAudioStatus);
199
200 mAudioStatusEventPending = false;
201
202 reset();
203}
204
205PreviewPlayerBase::~PreviewPlayerBase() {
206 if (mQueueStarted) {
207 mQueue.stop();
208 }
209
210 reset();
211
212 mClient.disconnect();
213}
214
215void PreviewPlayerBase::cancelPlayerEvents(bool keepBufferingGoing) {
216 mQueue.cancelEvent(mVideoEvent->eventID());
217 mVideoEventPending = false;
218 mQueue.cancelEvent(mStreamDoneEvent->eventID());
219 mStreamDoneEventPending = false;
220 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
221 mAudioStatusEventPending = false;
222 mQueue.cancelEvent(mVideoLagEvent->eventID());
223 mVideoLagEventPending = false;
224
225 if (!keepBufferingGoing) {
226 mQueue.cancelEvent(mBufferingEvent->eventID());
227 mBufferingEventPending = false;
228 }
229}
230
231void PreviewPlayerBase::setListener(const wp<MediaPlayerBase> &listener) {
232 Mutex::Autolock autoLock(mLock);
233 mListener = listener;
234}
235
236status_t PreviewPlayerBase::setDataSource(
237 const char *uri, const KeyedVector<String8, String8> *headers) {
238 Mutex::Autolock autoLock(mLock);
239 return setDataSource_l(uri, headers);
240}
241
242status_t PreviewPlayerBase::setDataSource_l(
243 const char *uri, const KeyedVector<String8, String8> *headers) {
244 reset_l();
245
246 mUri = uri;
247
248 if (headers) {
249 mUriHeaders = *headers;
250
251 ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
252 if (index >= 0) {
253 // Browser is in "incognito" mode, suppress logging URLs.
254
255 // This isn't something that should be passed to the server.
256 mUriHeaders.removeItemsAt(index);
257
258 mFlags |= INCOGNITO;
259 }
260 }
261
262 if (!(mFlags & INCOGNITO)) {
263 LOGI("setDataSource_l('%s')", mUri.string());
264 } else {
265 LOGI("setDataSource_l(URL suppressed)");
266 }
267
268 // The actual work will be done during preparation in the call to
269 // ::finishSetDataSource_l to avoid blocking the calling thread in
270 // setDataSource for any significant time.
271
272 return OK;
273}
274
275status_t PreviewPlayerBase::setDataSource(
276 int fd, int64_t offset, int64_t length) {
277 Mutex::Autolock autoLock(mLock);
278
279 reset_l();
280
281 sp<DataSource> dataSource = new FileSource(fd, offset, length);
282
283 status_t err = dataSource->initCheck();
284
285 if (err != OK) {
286 return err;
287 }
288
289 mFileSource = dataSource;
290
291 return setDataSource_l(dataSource);
292}
293
294status_t PreviewPlayerBase::setDataSource(const sp<IStreamSource> &source) {
295 return INVALID_OPERATION;
296}
297
298status_t PreviewPlayerBase::setDataSource_l(
299 const sp<DataSource> &dataSource) {
300 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
301
302 if (extractor == NULL) {
303 return UNKNOWN_ERROR;
304 }
305
306 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
307 if (mDecryptHandle != NULL) {
308 CHECK(mDrmManagerClient);
309 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
310 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
311 }
312 }
313
314 return setDataSource_l(extractor);
315}
316
317status_t PreviewPlayerBase::setDataSource_l(const sp<MediaExtractor> &extractor) {
318 // Attempt to approximate overall stream bitrate by summing all
319 // tracks' individual bitrates, if not all of them advertise bitrate,
320 // we have to fail.
321
322 int64_t totalBitRate = 0;
323
324 for (size_t i = 0; i < extractor->countTracks(); ++i) {
325 sp<MetaData> meta = extractor->getTrackMetaData(i);
326
327 int32_t bitrate;
328 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
329 totalBitRate = -1;
330 break;
331 }
332
333 totalBitRate += bitrate;
334 }
335
336 mBitrate = totalBitRate;
337
Steve Block2703f232011-10-20 11:56:09 +0100338 ALOGV("mBitrate = %lld bits/sec", mBitrate);
James Dongc9dedc42011-05-01 12:36:22 -0700339
340 bool haveAudio = false;
341 bool haveVideo = false;
342 for (size_t i = 0; i < extractor->countTracks(); ++i) {
343 sp<MetaData> meta = extractor->getTrackMetaData(i);
344
345 const char *mime;
346 CHECK(meta->findCString(kKeyMIMEType, &mime));
347
348 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
349 setVideoSource(extractor->getTrack(i));
350 haveVideo = true;
351
352 // Set the presentation/display size
353 int32_t displayWidth, displayHeight;
354 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
355 if (success) {
356 success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
357 }
358 if (success) {
359 mDisplayWidth = displayWidth;
360 mDisplayHeight = displayHeight;
361 }
362
363 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
364 setAudioSource(extractor->getTrack(i));
365 haveAudio = true;
366
367 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
368 // Only do this for vorbis audio, none of the other audio
369 // formats even support this ringtone specific hack and
370 // retrieving the metadata on some extractors may turn out
371 // to be very expensive.
372 sp<MetaData> fileMeta = extractor->getMetaData();
373 int32_t loop;
374 if (fileMeta != NULL
375 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
376 mFlags |= AUTO_LOOPING;
377 }
378 }
379 }
380
381 if (haveAudio && haveVideo) {
382 break;
383 }
384 }
385
386 if (!haveAudio && !haveVideo) {
387 return UNKNOWN_ERROR;
388 }
389
390 mExtractorFlags = extractor->flags();
391
392 return OK;
393}
394
395void PreviewPlayerBase::reset() {
396 Mutex::Autolock autoLock(mLock);
397 reset_l();
398}
399
400void PreviewPlayerBase::reset_l() {
401 mDisplayWidth = 0;
402 mDisplayHeight = 0;
403
404 if (mDecryptHandle != NULL) {
405 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
406 Playback::STOP, 0);
407 mDecryptHandle = NULL;
408 mDrmManagerClient = NULL;
409 }
410
411 if (mFlags & PLAYING) {
412 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
413 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
414 params |= IMediaPlayerService::kBatteryDataTrackAudio;
415 }
416 if (mVideoSource != NULL) {
417 params |= IMediaPlayerService::kBatteryDataTrackVideo;
418 }
419 addBatteryData(params);
420 }
421
422 if (mFlags & PREPARING) {
423 mFlags |= PREPARE_CANCELLED;
424 if (mConnectingDataSource != NULL) {
425 LOGI("interrupting the connection process");
426 mConnectingDataSource->disconnect();
James Dongc9dedc42011-05-01 12:36:22 -0700427 }
428
429 if (mFlags & PREPARING_CONNECTED) {
430 // We are basically done preparing, we're just buffering
431 // enough data to start playback, we can safely interrupt that.
432 finishAsyncPrepare_l();
433 }
434 }
435
436 while (mFlags & PREPARING) {
437 mPreparedCondition.wait(mLock);
438 }
439
440 cancelPlayerEvents();
441
442 mCachedSource.clear();
443 mAudioTrack.clear();
444 mVideoTrack.clear();
445
446 // Shutdown audio first, so that the respone to the reset request
447 // appears to happen instantaneously as far as the user is concerned
448 // If we did this later, audio would continue playing while we
449 // shutdown the video-related resources and the player appear to
450 // not be as responsive to a reset request.
451 if (mAudioPlayer == NULL && mAudioSource != NULL) {
452 // If we had an audio player, it would have effectively
453 // taken possession of the audio source and stopped it when
454 // _it_ is stopped. Otherwise this is still our responsibility.
455 mAudioSource->stop();
456 }
457 mAudioSource.clear();
458
459 mTimeSource = NULL;
460
461 delete mAudioPlayer;
462 mAudioPlayer = NULL;
463
464 mVideoRenderer.clear();
465
James Dongc9dedc42011-05-01 12:36:22 -0700466 if (mVideoSource != NULL) {
467 shutdownVideoDecoder_l();
468 }
469
470 mDurationUs = -1;
471 mFlags = 0;
472 mExtractorFlags = 0;
473 mTimeSourceDeltaUs = 0;
474 mVideoTimeUs = 0;
475
476 mSeeking = NO_SEEK;
477 mSeekNotificationSent = false;
478 mSeekTimeUs = 0;
479
480 mUri.setTo("");
481 mUriHeaders.clear();
482
483 mFileSource.clear();
484
485 mBitrate = -1;
486 mLastVideoTimeUs = -1;
487}
488
489void PreviewPlayerBase::notifyListener_l(int msg, int ext1, int ext2) {
490 if (mListener != NULL) {
491 sp<MediaPlayerBase> listener = mListener.promote();
492
493 if (listener != NULL) {
494 listener->sendEvent(msg, ext1, ext2);
495 }
496 }
497}
498
499bool PreviewPlayerBase::getBitrate(int64_t *bitrate) {
500 off64_t size;
501 if (mDurationUs >= 0 && mCachedSource != NULL
502 && mCachedSource->getSize(&size) == OK) {
503 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
504 return true;
505 }
506
507 if (mBitrate >= 0) {
508 *bitrate = mBitrate;
509 return true;
510 }
511
512 *bitrate = 0;
513
514 return false;
515}
516
517// Returns true iff cached duration is available/applicable.
518bool PreviewPlayerBase::getCachedDuration_l(int64_t *durationUs, bool *eos) {
519 int64_t bitrate;
520
Andreas Huber4a4a8f02011-10-12 15:08:42 -0700521 if (mCachedSource != NULL && getBitrate(&bitrate)) {
James Dongc9dedc42011-05-01 12:36:22 -0700522 status_t finalStatus;
523 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
524 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
525 *eos = (finalStatus != OK);
526 return true;
527 }
528
529 return false;
530}
531
532void PreviewPlayerBase::ensureCacheIsFetching_l() {
533 if (mCachedSource != NULL) {
534 mCachedSource->resumeFetchingIfNecessary();
535 }
536}
537
538void PreviewPlayerBase::onVideoLagUpdate() {
539 Mutex::Autolock autoLock(mLock);
540 if (!mVideoLagEventPending) {
541 return;
542 }
543 mVideoLagEventPending = false;
544
545 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
546 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
547
548 if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
Steve Block2703f232011-10-20 11:56:09 +0100549 ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
James Dongc9dedc42011-05-01 12:36:22 -0700550
551 notifyListener_l(
552 MEDIA_INFO,
553 MEDIA_INFO_VIDEO_TRACK_LAGGING,
554 videoLateByUs / 1000ll);
555 }
556
557 postVideoLagEvent_l();
558}
559
560void PreviewPlayerBase::onBufferingUpdate() {
561 Mutex::Autolock autoLock(mLock);
562 if (!mBufferingEventPending) {
563 return;
564 }
565 mBufferingEventPending = false;
566
567 if (mCachedSource != NULL) {
568 status_t finalStatus;
569 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
570 bool eos = (finalStatus != OK);
571
572 if (eos) {
573 if (finalStatus == ERROR_END_OF_STREAM) {
574 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
575 }
576 if (mFlags & PREPARING) {
Steve Block2703f232011-10-20 11:56:09 +0100577 ALOGV("cache has reached EOS, prepare is done.");
James Dongc9dedc42011-05-01 12:36:22 -0700578 finishAsyncPrepare_l();
579 }
580 } else {
581 int64_t bitrate;
582 if (getBitrate(&bitrate)) {
583 size_t cachedSize = mCachedSource->cachedSize();
584 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
585
586 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
587 if (percentage > 100) {
588 percentage = 100;
589 }
590
591 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
592 } else {
593 // We don't know the bitrate of the stream, use absolute size
594 // limits to maintain the cache.
595
596 if ((mFlags & PLAYING) && !eos
597 && (cachedDataRemaining < kLowWaterMarkBytes)) {
598 LOGI("cache is running low (< %d) , pausing.",
599 kLowWaterMarkBytes);
600 mFlags |= CACHE_UNDERRUN;
601 pause_l();
602 ensureCacheIsFetching_l();
603 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
604 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
605 if (mFlags & CACHE_UNDERRUN) {
606 LOGI("cache has filled up (> %d), resuming.",
607 kHighWaterMarkBytes);
608 mFlags &= ~CACHE_UNDERRUN;
609 play_l();
610 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
611 } else if (mFlags & PREPARING) {
Steve Block2703f232011-10-20 11:56:09 +0100612 ALOGV("cache has filled up (> %d), prepare is done",
James Dongc9dedc42011-05-01 12:36:22 -0700613 kHighWaterMarkBytes);
614 finishAsyncPrepare_l();
615 }
616 }
617 }
618 }
619 }
620
621 int64_t cachedDurationUs;
622 bool eos;
623 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Steve Block2703f232011-10-20 11:56:09 +0100624 ALOGV("cachedDurationUs = %.2f secs, eos=%d",
James Dongc9dedc42011-05-01 12:36:22 -0700625 cachedDurationUs / 1E6, eos);
626
James Dongc9dedc42011-05-01 12:36:22 -0700627 if ((mFlags & PLAYING) && !eos
628 && (cachedDurationUs < kLowWaterMarkUs)) {
629 LOGI("cache is running low (%.2f secs) , pausing.",
630 cachedDurationUs / 1E6);
631 mFlags |= CACHE_UNDERRUN;
632 pause_l();
633 ensureCacheIsFetching_l();
634 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber4a4a8f02011-10-12 15:08:42 -0700635 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
James Dongc9dedc42011-05-01 12:36:22 -0700636 if (mFlags & CACHE_UNDERRUN) {
637 LOGI("cache has filled up (%.2f secs), resuming.",
638 cachedDurationUs / 1E6);
639 mFlags &= ~CACHE_UNDERRUN;
640 play_l();
641 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
642 } else if (mFlags & PREPARING) {
Steve Block2703f232011-10-20 11:56:09 +0100643 ALOGV("cache has filled up (%.2f secs), prepare is done",
James Dongc9dedc42011-05-01 12:36:22 -0700644 cachedDurationUs / 1E6);
645 finishAsyncPrepare_l();
646 }
647 }
648 }
649
650 postBufferingEvent_l();
651}
652
653void PreviewPlayerBase::onStreamDone() {
654 // Posted whenever any stream finishes playing.
655
656 Mutex::Autolock autoLock(mLock);
657 if (!mStreamDoneEventPending) {
658 return;
659 }
660 mStreamDoneEventPending = false;
661
662 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Steve Block2703f232011-10-20 11:56:09 +0100663 ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
James Dongc9dedc42011-05-01 12:36:22 -0700664
665 notifyListener_l(
666 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
667
668 pause_l(true /* at eos */);
669
670 mFlags |= AT_EOS;
671 return;
672 }
673
674 const bool allDone =
675 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
676 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
677
678 if (!allDone) {
679 return;
680 }
681
682 if (mFlags & (LOOPING | AUTO_LOOPING)) {
683 seekTo_l(0);
684
685 if (mVideoSource != NULL) {
686 postVideoEvent_l();
687 }
688 } else {
Steve Block2703f232011-10-20 11:56:09 +0100689 ALOGV("MEDIA_PLAYBACK_COMPLETE");
James Dongc9dedc42011-05-01 12:36:22 -0700690 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
691
692 pause_l(true /* at eos */);
693
694 mFlags |= AT_EOS;
695 }
696}
697
698status_t PreviewPlayerBase::play() {
699 Mutex::Autolock autoLock(mLock);
700
701 mFlags &= ~CACHE_UNDERRUN;
702
703 return play_l();
704}
705
706status_t PreviewPlayerBase::play_l() {
707 mFlags &= ~SEEK_PREVIEW;
708
709 if (mFlags & PLAYING) {
710 return OK;
711 }
712
713 if (!(mFlags & PREPARED)) {
714 status_t err = prepare_l();
715
716 if (err != OK) {
717 return err;
718 }
719 }
720
721 mFlags |= PLAYING;
722 mFlags |= FIRST_FRAME;
723
724 if (mDecryptHandle != NULL) {
725 int64_t position;
726 getPosition(&position);
727 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
728 Playback::START, position / 1000);
729 }
730
731 if (mAudioSource != NULL) {
732 if (mAudioPlayer == NULL) {
733 if (mAudioSink != NULL) {
734 mAudioPlayer = new AudioPlayerBase(mAudioSink, this);
735 mAudioPlayer->setSource(mAudioSource);
736
737 mTimeSource = mAudioPlayer;
738
739 // If there was a seek request before we ever started,
740 // honor the request now.
741 // Make sure to do this before starting the audio player
742 // to avoid a race condition.
743 seekAudioIfNecessary_l();
744 }
745 }
746
747 CHECK(!(mFlags & AUDIO_RUNNING));
748
749 if (mVideoSource == NULL) {
750 status_t err = startAudioPlayer_l();
751
752 if (err != OK) {
753 delete mAudioPlayer;
754 mAudioPlayer = NULL;
755
756 mFlags &= ~(PLAYING | FIRST_FRAME);
757
758 if (mDecryptHandle != NULL) {
759 mDrmManagerClient->setPlaybackStatus(
760 mDecryptHandle, Playback::STOP, 0);
761 }
762
763 return err;
764 }
765 }
766 }
767
768 if (mTimeSource == NULL && mAudioPlayer == NULL) {
769 mTimeSource = &mSystemTimeSource;
770 }
771
772 if (mVideoSource != NULL) {
773 // Kick off video playback
774 postVideoEvent_l();
775
776 if (mAudioSource != NULL && mVideoSource != NULL) {
777 postVideoLagEvent_l();
778 }
779 }
780
781 if (mFlags & AT_EOS) {
782 // Legacy behaviour, if a stream finishes playing and then
783 // is started again, we play from the start...
784 seekTo_l(0);
785 }
786
787 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
788 | IMediaPlayerService::kBatteryDataTrackDecoder;
789 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
790 params |= IMediaPlayerService::kBatteryDataTrackAudio;
791 }
792 if (mVideoSource != NULL) {
793 params |= IMediaPlayerService::kBatteryDataTrackVideo;
794 }
795 addBatteryData(params);
796
797 return OK;
798}
799
800status_t PreviewPlayerBase::startAudioPlayer_l() {
801 CHECK(!(mFlags & AUDIO_RUNNING));
802
803 if (mAudioSource == NULL || mAudioPlayer == NULL) {
804 return OK;
805 }
806
807 if (!(mFlags & AUDIOPLAYER_STARTED)) {
808 mFlags |= AUDIOPLAYER_STARTED;
809
810 // We've already started the MediaSource in order to enable
811 // the prefetcher to read its data.
812 status_t err = mAudioPlayer->start(
813 true /* sourceAlreadyStarted */);
814
815 if (err != OK) {
816 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
817 return err;
818 }
819 } else {
820 mAudioPlayer->resume();
821 }
822
823 mFlags |= AUDIO_RUNNING;
824
825 mWatchForAudioEOS = true;
826
827 return OK;
828}
829
830void PreviewPlayerBase::notifyVideoSize_l() {
831 sp<MetaData> meta = mVideoSource->getFormat();
832
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800833 int32_t vWidth, vHeight;
James Dongc9dedc42011-05-01 12:36:22 -0700834 int32_t cropLeft, cropTop, cropRight, cropBottom;
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800835
836 CHECK(meta->findInt32(kKeyWidth, &vWidth));
837 CHECK(meta->findInt32(kKeyHeight, &vHeight));
838
839 mGivenWidth = vWidth;
840 mGivenHeight = vHeight;
841
James Dongc9dedc42011-05-01 12:36:22 -0700842 if (!meta->findRect(
843 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
James Dongc9dedc42011-05-01 12:36:22 -0700844
845 cropLeft = cropTop = 0;
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800846 cropRight = vWidth - 1;
847 cropBottom = vHeight - 1;
James Dongc9dedc42011-05-01 12:36:22 -0700848
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800849 LOGD("got dimensions only %d x %d", vWidth, vHeight);
James Dongc9dedc42011-05-01 12:36:22 -0700850 } else {
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800851 LOGD("got crop rect %d, %d, %d, %d",
James Dongc9dedc42011-05-01 12:36:22 -0700852 cropLeft, cropTop, cropRight, cropBottom);
853 }
854
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800855 mCropRect.left = cropLeft;
856 mCropRect.right = cropRight;
857 mCropRect.top = cropTop;
858 mCropRect.bottom = cropBottom;
859
James Dongc9dedc42011-05-01 12:36:22 -0700860 int32_t displayWidth;
861 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
Steve Block2703f232011-10-20 11:56:09 +0100862 ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
James Dongc9dedc42011-05-01 12:36:22 -0700863 mDisplayWidth = displayWidth;
864 }
865 int32_t displayHeight;
866 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
Steve Block2703f232011-10-20 11:56:09 +0100867 ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
James Dongc9dedc42011-05-01 12:36:22 -0700868 mDisplayHeight = displayHeight;
869 }
870
871 int32_t usableWidth = cropRight - cropLeft + 1;
872 int32_t usableHeight = cropBottom - cropTop + 1;
873 if (mDisplayWidth != 0) {
874 usableWidth = mDisplayWidth;
875 }
876 if (mDisplayHeight != 0) {
877 usableHeight = mDisplayHeight;
878 }
879
880 int32_t rotationDegrees;
881 if (!mVideoTrack->getFormat()->findInt32(
882 kKeyRotation, &rotationDegrees)) {
883 rotationDegrees = 0;
884 }
885
886 if (rotationDegrees == 90 || rotationDegrees == 270) {
887 notifyListener_l(
888 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
889 } else {
890 notifyListener_l(
891 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
892 }
893}
894
895void PreviewPlayerBase::initRenderer_l() {
896 if (mNativeWindow == NULL) {
897 return;
898 }
899
900 sp<MetaData> meta = mVideoSource->getFormat();
901
902 int32_t format;
903 const char *component;
James Dongc9dedc42011-05-01 12:36:22 -0700904 CHECK(meta->findInt32(kKeyColorFormat, &format));
905 CHECK(meta->findCString(kKeyDecoderComponent, &component));
James Dongc9dedc42011-05-01 12:36:22 -0700906
907 int32_t rotationDegrees;
908 if (!mVideoTrack->getFormat()->findInt32(
909 kKeyRotation, &rotationDegrees)) {
910 rotationDegrees = 0;
911 }
912
913 mVideoRenderer.clear();
914
915 // Must ensure that mVideoRenderer's destructor is actually executed
916 // before creating a new one.
917 IPCThreadState::self()->flushCommands();
918
919 if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
920 // Hardware decoders avoid the CPU color conversion by decoding
921 // directly to ANativeBuffers, so we must use a renderer that
922 // just pushes those buffers to the ANativeWindow.
923 mVideoRenderer =
924 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
925 } else {
926 // Other decoders are instantiated locally and as a consequence
927 // allocate their buffers in local address space. This renderer
928 // then performs a color conversion and copy to get the data
929 // into the ANativeBuffer.
930 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
931 }
932}
933
934status_t PreviewPlayerBase::pause() {
935 Mutex::Autolock autoLock(mLock);
936
937 mFlags &= ~CACHE_UNDERRUN;
938
939 return pause_l();
940}
941
942status_t PreviewPlayerBase::pause_l(bool at_eos) {
943 if (!(mFlags & PLAYING)) {
944 return OK;
945 }
946
947 cancelPlayerEvents(true /* keepBufferingGoing */);
948
949 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
950 if (at_eos) {
951 // If we played the audio stream to completion we
952 // want to make sure that all samples remaining in the audio
953 // track's queue are played out.
954 mAudioPlayer->pause(true /* playPendingSamples */);
955 } else {
956 mAudioPlayer->pause();
957 }
958
959 mFlags &= ~AUDIO_RUNNING;
960 }
961
962 mFlags &= ~PLAYING;
963
964 if (mDecryptHandle != NULL) {
965 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
966 Playback::PAUSE, 0);
967 }
968
969 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
970 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
971 params |= IMediaPlayerService::kBatteryDataTrackAudio;
972 }
973 if (mVideoSource != NULL) {
974 params |= IMediaPlayerService::kBatteryDataTrackVideo;
975 }
976
977 addBatteryData(params);
978
979 return OK;
980}
981
982bool PreviewPlayerBase::isPlaying() const {
983 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
984}
985
986void PreviewPlayerBase::setSurface(const sp<Surface> &surface) {
987 Mutex::Autolock autoLock(mLock);
988
989 mSurface = surface;
990 setNativeWindow_l(surface);
991}
992
993void PreviewPlayerBase::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
994 Mutex::Autolock autoLock(mLock);
995
996 mSurface.clear();
997 if (surfaceTexture != NULL) {
998 setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
999 }
1000}
1001
1002void PreviewPlayerBase::shutdownVideoDecoder_l() {
1003 if (mVideoBuffer) {
1004 mVideoBuffer->release();
1005 mVideoBuffer = NULL;
1006 }
1007
1008 mVideoSource->stop();
1009
1010 // The following hack is necessary to ensure that the OMX
1011 // component is completely released by the time we may try
1012 // to instantiate it again.
1013 wp<MediaSource> tmp = mVideoSource;
1014 mVideoSource.clear();
1015 while (tmp.promote() != NULL) {
1016 usleep(1000);
1017 }
1018 IPCThreadState::self()->flushCommands();
1019}
1020
1021void PreviewPlayerBase::setNativeWindow_l(const sp<ANativeWindow> &native) {
1022 mNativeWindow = native;
1023
1024 if (mVideoSource == NULL) {
1025 return;
1026 }
1027
1028 LOGI("attempting to reconfigure to use new surface");
1029
1030 bool wasPlaying = (mFlags & PLAYING) != 0;
1031
1032 pause_l();
1033 mVideoRenderer.clear();
1034
1035 shutdownVideoDecoder_l();
1036
1037 CHECK_EQ(initVideoDecoder(), (status_t)OK);
1038
1039 if (mLastVideoTimeUs >= 0) {
1040 mSeeking = SEEK;
1041 mSeekNotificationSent = true;
1042 mSeekTimeUs = mLastVideoTimeUs;
1043 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1044 }
1045
1046 if (wasPlaying) {
1047 play_l();
1048 }
1049}
1050
1051void PreviewPlayerBase::setAudioSink(
1052 const sp<MediaPlayerBase::AudioSink> &audioSink) {
1053 Mutex::Autolock autoLock(mLock);
1054
1055 mAudioSink = audioSink;
1056}
1057
1058status_t PreviewPlayerBase::setLooping(bool shouldLoop) {
1059 Mutex::Autolock autoLock(mLock);
1060
1061 mFlags = mFlags & ~LOOPING;
1062
1063 if (shouldLoop) {
1064 mFlags |= LOOPING;
1065 }
1066
1067 return OK;
1068}
1069
1070status_t PreviewPlayerBase::getDuration(int64_t *durationUs) {
1071 Mutex::Autolock autoLock(mMiscStateLock);
1072
1073 if (mDurationUs < 0) {
1074 return UNKNOWN_ERROR;
1075 }
1076
1077 *durationUs = mDurationUs;
1078
1079 return OK;
1080}
1081
1082status_t PreviewPlayerBase::getPosition(int64_t *positionUs) {
Andreas Huber4a4a8f02011-10-12 15:08:42 -07001083 if (mSeeking != NO_SEEK) {
James Dongc9dedc42011-05-01 12:36:22 -07001084 *positionUs = mSeekTimeUs;
1085 } else if (mVideoSource != NULL
1086 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
1087 Mutex::Autolock autoLock(mMiscStateLock);
1088 *positionUs = mVideoTimeUs;
1089 } else if (mAudioPlayer != NULL) {
1090 *positionUs = mAudioPlayer->getMediaTimeUs();
1091 } else {
1092 *positionUs = 0;
1093 }
1094
1095 return OK;
1096}
1097
1098status_t PreviewPlayerBase::seekTo(int64_t timeUs) {
1099 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
1100 Mutex::Autolock autoLock(mLock);
1101 return seekTo_l(timeUs);
1102 }
1103
1104 return OK;
1105}
1106
James Dongc9dedc42011-05-01 12:36:22 -07001107status_t PreviewPlayerBase::seekTo_l(int64_t timeUs) {
James Dongc9dedc42011-05-01 12:36:22 -07001108 if (mFlags & CACHE_UNDERRUN) {
1109 mFlags &= ~CACHE_UNDERRUN;
1110 play_l();
1111 }
1112
1113 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
1114 // Video playback completed before, there's no pending
1115 // video event right now. In order for this new seek
1116 // to be honored, we need to post one.
1117
1118 postVideoEvent_l();
1119 }
1120
1121 mSeeking = SEEK;
1122 mSeekNotificationSent = false;
1123 mSeekTimeUs = timeUs;
1124 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1125
1126 seekAudioIfNecessary_l();
1127
1128 if (!(mFlags & PLAYING)) {
Steve Block2703f232011-10-20 11:56:09 +01001129 ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
James Dongc9dedc42011-05-01 12:36:22 -07001130 " immediately.");
1131
1132 notifyListener_l(MEDIA_SEEK_COMPLETE);
1133 mSeekNotificationSent = true;
1134
1135 if ((mFlags & PREPARED) && mVideoSource != NULL) {
1136 mFlags |= SEEK_PREVIEW;
1137 postVideoEvent_l();
1138 }
1139 }
1140
1141 return OK;
1142}
1143
1144void PreviewPlayerBase::seekAudioIfNecessary_l() {
1145 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
1146 mAudioPlayer->seekTo(mSeekTimeUs);
1147
1148 mWatchForAudioSeekComplete = true;
1149 mWatchForAudioEOS = true;
1150
1151 if (mDecryptHandle != NULL) {
1152 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1153 Playback::PAUSE, 0);
1154 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1155 Playback::START, mSeekTimeUs / 1000);
1156 }
1157 }
1158}
1159
1160void PreviewPlayerBase::setAudioSource(sp<MediaSource> source) {
1161 CHECK(source != NULL);
1162
1163 mAudioTrack = source;
1164}
1165
1166status_t PreviewPlayerBase::initAudioDecoder() {
1167 sp<MetaData> meta = mAudioTrack->getFormat();
1168
1169 const char *mime;
1170 CHECK(meta->findCString(kKeyMIMEType, &mime));
1171
1172 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1173 mAudioSource = mAudioTrack;
1174 } else {
1175 mAudioSource = OMXCodec::Create(
1176 mClient.interface(), mAudioTrack->getFormat(),
1177 false, // createEncoder
1178 mAudioTrack);
1179 }
1180
1181 if (mAudioSource != NULL) {
1182 int64_t durationUs;
1183 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1184 Mutex::Autolock autoLock(mMiscStateLock);
1185 if (mDurationUs < 0 || durationUs > mDurationUs) {
1186 mDurationUs = durationUs;
1187 }
1188 }
1189
1190 status_t err = mAudioSource->start();
1191
1192 if (err != OK) {
1193 mAudioSource.clear();
1194 return err;
1195 }
1196 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1197 // For legacy reasons we're simply going to ignore the absence
1198 // of an audio decoder for QCELP instead of aborting playback
1199 // altogether.
1200 return OK;
1201 }
1202
1203 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1204}
1205
1206void PreviewPlayerBase::setVideoSource(sp<MediaSource> source) {
1207 CHECK(source != NULL);
1208
1209 mVideoTrack = source;
1210}
1211
1212status_t PreviewPlayerBase::initVideoDecoder(uint32_t flags) {
1213
1214 // Either the application or the DRM system can independently say
1215 // that there must be a hardware-protected path to an external video sink.
1216 // For now we always require a hardware-protected path to external video sink
1217 // if content is DRMed, but eventually this could be optional per DRM agent.
1218 // When the application wants protection, then
1219 // (USE_SURFACE_ALLOC && (mSurface != 0) &&
1220 // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
1221 // will be true, but that part is already handled by SurfaceFlinger.
1222
1223#ifdef DEBUG_HDCP
1224 // For debugging, we allow a system property to control the protected usage.
1225 // In case of uninitialized or unexpected property, we default to "DRM only".
1226 bool setProtectionBit = false;
1227 char value[PROPERTY_VALUE_MAX];
1228 if (property_get("persist.sys.hdcp_checking", value, NULL)) {
1229 if (!strcmp(value, "never")) {
1230 // nop
1231 } else if (!strcmp(value, "always")) {
1232 setProtectionBit = true;
1233 } else if (!strcmp(value, "drm-only")) {
1234 if (mDecryptHandle != NULL) {
1235 setProtectionBit = true;
1236 }
1237 // property value is empty, or unexpected value
1238 } else {
1239 if (mDecryptHandle != NULL) {
1240 setProtectionBit = true;
1241 }
1242 }
1243 // can' read property value
1244 } else {
1245 if (mDecryptHandle != NULL) {
1246 setProtectionBit = true;
1247 }
1248 }
1249 // note that usage bit is already cleared, so no need to clear it in the "else" case
1250 if (setProtectionBit) {
1251 flags |= OMXCodec::kEnableGrallocUsageProtected;
1252 }
1253#else
1254 if (mDecryptHandle != NULL) {
1255 flags |= OMXCodec::kEnableGrallocUsageProtected;
1256 }
1257#endif
Steve Block2703f232011-10-20 11:56:09 +01001258 ALOGV("initVideoDecoder flags=0x%x", flags);
James Dongc9dedc42011-05-01 12:36:22 -07001259 mVideoSource = OMXCodec::Create(
1260 mClient.interface(), mVideoTrack->getFormat(),
1261 false, // createEncoder
1262 mVideoTrack,
1263 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
1264
1265 if (mVideoSource != NULL) {
1266 int64_t durationUs;
1267 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1268 Mutex::Autolock autoLock(mMiscStateLock);
1269 if (mDurationUs < 0 || durationUs > mDurationUs) {
1270 mDurationUs = durationUs;
1271 }
1272 }
1273
1274 status_t err = mVideoSource->start();
1275
1276 if (err != OK) {
1277 mVideoSource.clear();
1278 return err;
1279 }
1280 }
1281
1282 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1283}
1284
1285void PreviewPlayerBase::finishSeekIfNecessary(int64_t videoTimeUs) {
1286 if (mSeeking == SEEK_VIDEO_ONLY) {
1287 mSeeking = NO_SEEK;
1288 return;
1289 }
1290
1291 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1292 return;
1293 }
1294
1295 if (mAudioPlayer != NULL) {
Steve Block2703f232011-10-20 11:56:09 +01001296 ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001297
1298 // If we don't have a video time, seek audio to the originally
1299 // requested seek time instead.
1300
1301 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1302 mWatchForAudioSeekComplete = true;
1303 mWatchForAudioEOS = true;
1304 } else if (!mSeekNotificationSent) {
1305 // If we're playing video only, report seek complete now,
1306 // otherwise audio player will notify us later.
1307 notifyListener_l(MEDIA_SEEK_COMPLETE);
1308 mSeekNotificationSent = true;
1309 }
1310
1311 mFlags |= FIRST_FRAME;
1312 mSeeking = NO_SEEK;
1313
1314 if (mDecryptHandle != NULL) {
1315 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1316 Playback::PAUSE, 0);
1317 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1318 Playback::START, videoTimeUs / 1000);
1319 }
1320}
1321
1322void PreviewPlayerBase::onVideoEvent() {
1323 Mutex::Autolock autoLock(mLock);
1324 if (!mVideoEventPending) {
1325 // The event has been cancelled in reset_l() but had already
1326 // been scheduled for execution at that time.
1327 return;
1328 }
1329 mVideoEventPending = false;
1330
1331 if (mSeeking != NO_SEEK) {
1332 if (mVideoBuffer) {
1333 mVideoBuffer->release();
1334 mVideoBuffer = NULL;
1335 }
1336
1337 if (mSeeking == SEEK && mCachedSource != NULL && mAudioSource != NULL
1338 && !(mFlags & SEEK_PREVIEW)) {
1339 // We're going to seek the video source first, followed by
1340 // the audio source.
1341 // In order to avoid jumps in the DataSource offset caused by
1342 // the audio codec prefetching data from the old locations
1343 // while the video codec is already reading data from the new
1344 // locations, we'll "pause" the audio source, causing it to
1345 // stop reading input data until a subsequent seek.
1346
1347 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1348 mAudioPlayer->pause();
1349
1350 mFlags &= ~AUDIO_RUNNING;
1351 }
1352 mAudioSource->pause();
1353 }
1354 }
1355
1356 if (!mVideoBuffer) {
1357 MediaSource::ReadOptions options;
1358 if (mSeeking != NO_SEEK) {
Steve Block2703f232011-10-20 11:56:09 +01001359 ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001360
1361 options.setSeekTo(
1362 mSeekTimeUs,
1363 mSeeking == SEEK_VIDEO_ONLY
1364 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
1365 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1366 }
1367 for (;;) {
Chih-Chung Chang43fcc392011-08-02 16:17:39 +08001368 status_t err = mVideoSource->read(&mVideoBuffer, &options);
James Dongc9dedc42011-05-01 12:36:22 -07001369 options.clearSeekTo();
1370
1371 if (err != OK) {
1372 CHECK(mVideoBuffer == NULL);
1373
1374 if (err == INFO_FORMAT_CHANGED) {
Steve Block2703f232011-10-20 11:56:09 +01001375 ALOGV("VideoSource signalled format change.");
James Dongc9dedc42011-05-01 12:36:22 -07001376
1377 notifyVideoSize_l();
1378
1379 if (mVideoRenderer != NULL) {
1380 mVideoRendererIsPreview = false;
1381 initRenderer_l();
1382 }
1383 continue;
1384 }
1385
1386 // So video playback is complete, but we may still have
1387 // a seek request pending that needs to be applied
1388 // to the audio track.
1389 if (mSeeking != NO_SEEK) {
Steve Block2703f232011-10-20 11:56:09 +01001390 ALOGV("video stream ended while seeking!");
James Dongc9dedc42011-05-01 12:36:22 -07001391 }
1392 finishSeekIfNecessary(-1);
1393
1394 if (mAudioPlayer != NULL
1395 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1396 startAudioPlayer_l();
1397 }
1398
1399 mFlags |= VIDEO_AT_EOS;
1400 postStreamDoneEvent_l(err);
1401 return;
1402 }
1403
1404 if (mVideoBuffer->range_length() == 0) {
1405 // Some decoders, notably the PV AVC software decoder
1406 // return spurious empty buffers that we just want to ignore.
1407
1408 mVideoBuffer->release();
1409 mVideoBuffer = NULL;
1410 continue;
1411 }
1412
1413 break;
1414 }
1415 }
1416
1417 int64_t timeUs;
1418 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1419
1420 mLastVideoTimeUs = timeUs;
1421
1422 if (mSeeking == SEEK_VIDEO_ONLY) {
1423 if (mSeekTimeUs > timeUs) {
1424 LOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
1425 mSeekTimeUs, timeUs);
1426 }
1427 }
1428
1429 {
1430 Mutex::Autolock autoLock(mMiscStateLock);
1431 mVideoTimeUs = timeUs;
1432 }
1433
1434 SeekType wasSeeking = mSeeking;
1435 finishSeekIfNecessary(timeUs);
1436
1437 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1438 status_t err = startAudioPlayer_l();
1439 if (err != OK) {
1440 LOGE("Startung the audio player failed w/ err %d", err);
1441 return;
1442 }
1443 }
1444
1445 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1446
1447 if (mFlags & FIRST_FRAME) {
1448 mFlags &= ~FIRST_FRAME;
1449 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1450 }
1451
1452 int64_t realTimeUs, mediaTimeUs;
1453 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1454 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1455 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1456 }
1457
1458 if (wasSeeking == SEEK_VIDEO_ONLY) {
1459 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1460
1461 int64_t latenessUs = nowUs - timeUs;
1462
1463 if (latenessUs > 0) {
1464 LOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
1465 }
1466 }
1467
1468 if (wasSeeking == NO_SEEK) {
1469 // Let's display the first frame after seeking right away.
1470
1471 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1472
1473 int64_t latenessUs = nowUs - timeUs;
1474
1475 if (latenessUs > 500000ll
James Dongc9dedc42011-05-01 12:36:22 -07001476 && mAudioPlayer != NULL
1477 && mAudioPlayer->getMediaTimeMapping(
1478 &realTimeUs, &mediaTimeUs)) {
1479 LOGI("we're much too late (%.2f secs), video skipping ahead",
1480 latenessUs / 1E6);
1481
1482 mVideoBuffer->release();
1483 mVideoBuffer = NULL;
1484
1485 mSeeking = SEEK_VIDEO_ONLY;
1486 mSeekTimeUs = mediaTimeUs;
1487
1488 postVideoEvent_l();
1489 return;
1490 }
1491
1492 if (latenessUs > 40000) {
1493 // We're more than 40ms late.
Steve Block2703f232011-10-20 11:56:09 +01001494 ALOGV("we're late by %lld us (%.2f secs), dropping frame",
James Dongc9dedc42011-05-01 12:36:22 -07001495 latenessUs, latenessUs / 1E6);
1496 mVideoBuffer->release();
1497 mVideoBuffer = NULL;
1498
1499 postVideoEvent_l();
1500 return;
1501 }
1502
1503 if (latenessUs < -10000) {
1504 // We're more than 10ms early.
1505
1506 postVideoEvent_l(10000);
1507 return;
1508 }
1509 }
1510
1511 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1512 mVideoRendererIsPreview = false;
1513
1514 initRenderer_l();
1515 }
1516
1517 if (mVideoRenderer != NULL) {
1518 mVideoRenderer->render(mVideoBuffer);
1519 }
1520
1521 mVideoBuffer->release();
1522 mVideoBuffer = NULL;
1523
1524 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
1525 mFlags &= ~SEEK_PREVIEW;
1526 return;
1527 }
1528
1529 postVideoEvent_l();
1530}
1531
1532void PreviewPlayerBase::postVideoEvent_l(int64_t delayUs) {
1533 if (mVideoEventPending) {
1534 return;
1535 }
1536
1537 mVideoEventPending = true;
1538 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1539}
1540
1541void PreviewPlayerBase::postStreamDoneEvent_l(status_t status) {
1542 if (mStreamDoneEventPending) {
1543 return;
1544 }
1545 mStreamDoneEventPending = true;
1546
1547 mStreamDoneStatus = status;
1548 mQueue.postEvent(mStreamDoneEvent);
1549}
1550
1551void PreviewPlayerBase::postBufferingEvent_l() {
1552 if (mBufferingEventPending) {
1553 return;
1554 }
1555 mBufferingEventPending = true;
1556 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1557}
1558
1559void PreviewPlayerBase::postVideoLagEvent_l() {
1560 if (mVideoLagEventPending) {
1561 return;
1562 }
1563 mVideoLagEventPending = true;
1564 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
1565}
1566
1567void PreviewPlayerBase::postCheckAudioStatusEvent_l(int64_t delayUs) {
1568 if (mAudioStatusEventPending) {
1569 return;
1570 }
1571 mAudioStatusEventPending = true;
1572 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
1573}
1574
1575void PreviewPlayerBase::onCheckAudioStatus() {
1576 Mutex::Autolock autoLock(mLock);
1577 if (!mAudioStatusEventPending) {
1578 // Event was dispatched and while we were blocking on the mutex,
1579 // has already been cancelled.
1580 return;
1581 }
1582
1583 mAudioStatusEventPending = false;
1584
1585 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1586 mWatchForAudioSeekComplete = false;
1587
1588 if (!mSeekNotificationSent) {
1589 notifyListener_l(MEDIA_SEEK_COMPLETE);
1590 mSeekNotificationSent = true;
1591 }
1592
1593 mSeeking = NO_SEEK;
1594 }
1595
1596 status_t finalStatus;
1597 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
1598 mWatchForAudioEOS = false;
1599 mFlags |= AUDIO_AT_EOS;
1600 mFlags |= FIRST_FRAME;
1601 postStreamDoneEvent_l(finalStatus);
1602 }
1603}
1604
1605status_t PreviewPlayerBase::prepare() {
1606 Mutex::Autolock autoLock(mLock);
1607 return prepare_l();
1608}
1609
1610status_t PreviewPlayerBase::prepare_l() {
1611 if (mFlags & PREPARED) {
1612 return OK;
1613 }
1614
1615 if (mFlags & PREPARING) {
1616 return UNKNOWN_ERROR;
1617 }
1618
1619 mIsAsyncPrepare = false;
1620 status_t err = prepareAsync_l();
1621
1622 if (err != OK) {
1623 return err;
1624 }
1625
1626 while (mFlags & PREPARING) {
1627 mPreparedCondition.wait(mLock);
1628 }
1629
1630 return mPrepareResult;
1631}
1632
1633status_t PreviewPlayerBase::prepareAsync() {
1634 Mutex::Autolock autoLock(mLock);
1635
1636 if (mFlags & PREPARING) {
1637 return UNKNOWN_ERROR; // async prepare already pending
1638 }
1639
1640 mIsAsyncPrepare = true;
1641 return prepareAsync_l();
1642}
1643
1644status_t PreviewPlayerBase::prepareAsync_l() {
1645 if (mFlags & PREPARING) {
1646 return UNKNOWN_ERROR; // async prepare already pending
1647 }
1648
1649 if (!mQueueStarted) {
1650 mQueue.start();
1651 mQueueStarted = true;
1652 }
1653
1654 mFlags |= PREPARING;
1655 mAsyncPrepareEvent = new AwesomeEvent(
1656 this, &PreviewPlayerBase::onPrepareAsyncEvent);
1657
1658 mQueue.postEvent(mAsyncPrepareEvent);
1659
1660 return OK;
1661}
1662
1663status_t PreviewPlayerBase::finishSetDataSource_l() {
1664 sp<DataSource> dataSource;
1665
1666 if (!strncasecmp("http://", mUri.string(), 7)
1667 || !strncasecmp("https://", mUri.string(), 8)) {
1668 mConnectingDataSource = HTTPBase::Create(
1669 (mFlags & INCOGNITO)
1670 ? HTTPBase::kFlagIncognito
1671 : 0);
1672
1673 mLock.unlock();
1674 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
1675 mLock.lock();
1676
1677 if (err != OK) {
1678 mConnectingDataSource.clear();
1679
1680 LOGI("mConnectingDataSource->connect() returned %d", err);
1681 return err;
1682 }
1683
1684#if 0
1685 mCachedSource = new NuCachedSource2(
1686 new ThrottledSource(
1687 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1688#else
1689 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1690#endif
1691 mConnectingDataSource.clear();
1692
1693 dataSource = mCachedSource;
1694
1695 String8 contentType = dataSource->getMIMEType();
1696
1697 if (strncasecmp(contentType.string(), "audio/", 6)) {
1698 // We're not doing this for streams that appear to be audio-only
1699 // streams to ensure that even low bandwidth streams start
1700 // playing back fairly instantly.
1701
1702 // We're going to prefill the cache before trying to instantiate
1703 // the extractor below, as the latter is an operation that otherwise
1704 // could block on the datasource for a significant amount of time.
1705 // During that time we'd be unable to abort the preparation phase
1706 // without this prefill.
1707
1708 mLock.unlock();
1709
1710 for (;;) {
1711 status_t finalStatus;
1712 size_t cachedDataRemaining =
1713 mCachedSource->approxDataRemaining(&finalStatus);
1714
1715 if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
1716 || (mFlags & PREPARE_CANCELLED)) {
1717 break;
1718 }
1719
1720 usleep(200000);
1721 }
1722
1723 mLock.lock();
1724 }
1725
1726 if (mFlags & PREPARE_CANCELLED) {
1727 LOGI("Prepare cancelled while waiting for initial cache fill.");
1728 return UNKNOWN_ERROR;
1729 }
James Dongc9dedc42011-05-01 12:36:22 -07001730 } else {
1731 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1732 }
1733
1734 if (dataSource == NULL) {
1735 return UNKNOWN_ERROR;
1736 }
1737
1738 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1739
1740 if (extractor == NULL) {
1741 return UNKNOWN_ERROR;
1742 }
1743
1744 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
1745
1746 if (mDecryptHandle != NULL) {
1747 CHECK(mDrmManagerClient);
1748 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
1749 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
1750 }
1751 }
1752
1753 return setDataSource_l(extractor);
1754}
1755
1756void PreviewPlayerBase::abortPrepare(status_t err) {
1757 CHECK(err != OK);
1758
1759 if (mIsAsyncPrepare) {
1760 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1761 }
1762
1763 mPrepareResult = err;
1764 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1765 mAsyncPrepareEvent = NULL;
1766 mPreparedCondition.broadcast();
1767}
1768
1769// static
1770bool PreviewPlayerBase::ContinuePreparation(void *cookie) {
1771 PreviewPlayerBase *me = static_cast<PreviewPlayerBase *>(cookie);
1772
1773 return (me->mFlags & PREPARE_CANCELLED) == 0;
1774}
1775
1776void PreviewPlayerBase::onPrepareAsyncEvent() {
1777 Mutex::Autolock autoLock(mLock);
1778
1779 if (mFlags & PREPARE_CANCELLED) {
1780 LOGI("prepare was cancelled before doing anything");
1781 abortPrepare(UNKNOWN_ERROR);
1782 return;
1783 }
1784
1785 if (mUri.size() > 0) {
1786 status_t err = finishSetDataSource_l();
1787
1788 if (err != OK) {
1789 abortPrepare(err);
1790 return;
1791 }
1792 }
1793
1794 if (mVideoTrack != NULL && mVideoSource == NULL) {
1795 status_t err = initVideoDecoder();
1796
1797 if (err != OK) {
1798 abortPrepare(err);
1799 return;
1800 }
1801 }
1802
1803 if (mAudioTrack != NULL && mAudioSource == NULL) {
1804 status_t err = initAudioDecoder();
1805
1806 if (err != OK) {
1807 abortPrepare(err);
1808 return;
1809 }
1810 }
1811
1812 mFlags |= PREPARING_CONNECTED;
1813
Andreas Huber4a4a8f02011-10-12 15:08:42 -07001814 if (mCachedSource != NULL) {
James Dongc9dedc42011-05-01 12:36:22 -07001815 postBufferingEvent_l();
1816 } else {
1817 finishAsyncPrepare_l();
1818 }
1819}
1820
1821void PreviewPlayerBase::finishAsyncPrepare_l() {
1822 if (mIsAsyncPrepare) {
1823 if (mVideoSource == NULL) {
1824 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1825 } else {
1826 notifyVideoSize_l();
1827 }
1828
1829 notifyListener_l(MEDIA_PREPARED);
1830 }
1831
1832 mPrepareResult = OK;
1833 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1834 mFlags |= PREPARED;
1835 mAsyncPrepareEvent = NULL;
1836 mPreparedCondition.broadcast();
1837}
1838
1839uint32_t PreviewPlayerBase::flags() const {
1840 return mExtractorFlags;
1841}
1842
1843void PreviewPlayerBase::postAudioEOS(int64_t delayUs) {
1844 Mutex::Autolock autoLock(mLock);
1845 postCheckAudioStatusEvent_l(delayUs);
1846}
1847
1848void PreviewPlayerBase::postAudioSeekComplete() {
1849 Mutex::Autolock autoLock(mLock);
1850 postCheckAudioStatusEvent_l(0 /* delayUs */);
1851}
1852
1853status_t PreviewPlayerBase::setParameter(int key, const Parcel &request) {
1854 return OK;
1855}
1856
1857status_t PreviewPlayerBase::getParameter(int key, Parcel *reply) {
1858 return OK;
1859}
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +08001860
James Dongc9dedc42011-05-01 12:36:22 -07001861} // namespace android