blob: 84bff9f449bef031c2fa7419d170d4a6bbb38fad [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
James Dongc9dedc42011-05-01 12:36:22 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "PreviewPlayerBase"
19#include <utils/Log.h>
20
21#include <dlfcn.h>
22
James Dongc9dedc42011-05-01 12:36:22 -070023#include "PreviewPlayerBase.h"
24#include "AudioPlayerBase.h"
25#include "include/SoftwareRenderer.h"
26#include "include/NuCachedSource2.h"
27#include "include/ThrottledSource.h"
28#include "include/MPEG2TSExtractor.h"
29
30#include <binder/IPCThreadState.h>
31#include <binder/IServiceManager.h>
32#include <media/IMediaPlayerService.h>
33#include <media/stagefright/foundation/hexdump.h>
34#include <media/stagefright/foundation/ADebug.h>
35#include <media/stagefright/DataSource.h>
36#include <media/stagefright/FileSource.h>
37#include <media/stagefright/MediaBuffer.h>
38#include <media/stagefright/MediaDefs.h>
39#include <media/stagefright/MediaExtractor.h>
40#include <media/stagefright/MediaSource.h>
41#include <media/stagefright/MetaData.h>
42#include <media/stagefright/OMXCodec.h>
43
44#include <surfaceflinger/Surface.h>
45#include <gui/ISurfaceTexture.h>
46#include <gui/SurfaceTextureClient.h>
47#include <surfaceflinger/ISurfaceComposer.h>
48
James Dongc9dedc42011-05-01 12:36:22 -070049#include <cutils/properties.h>
50
51#define USE_SURFACE_ALLOC 1
52
53namespace android {
54
55static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
56static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
James Dongc9dedc42011-05-01 12:36:22 -070057static const size_t kLowWaterMarkBytes = 40000;
58static const size_t kHighWaterMarkBytes = 200000;
59
60struct AwesomeEvent : public TimedEventQueue::Event {
61 AwesomeEvent(
62 PreviewPlayerBase *player,
63 void (PreviewPlayerBase::*method)())
64 : mPlayer(player),
65 mMethod(method) {
66 }
67
68protected:
69 virtual ~AwesomeEvent() {}
70
71 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
72 (mPlayer->*mMethod)();
73 }
74
75private:
76 PreviewPlayerBase *mPlayer;
77 void (PreviewPlayerBase::*mMethod)();
78
79 AwesomeEvent(const AwesomeEvent &);
80 AwesomeEvent &operator=(const AwesomeEvent &);
81};
82
83struct AwesomeLocalRenderer : public AwesomeRenderer {
84 AwesomeLocalRenderer(
85 const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
86 : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
87 }
88
89 virtual void render(MediaBuffer *buffer) {
90 render((const uint8_t *)buffer->data() + buffer->range_offset(),
91 buffer->range_length());
92 }
93
94 void render(const void *data, size_t size) {
95 mTarget->render(data, size, NULL);
96 }
97
98protected:
99 virtual ~AwesomeLocalRenderer() {
100 delete mTarget;
101 mTarget = NULL;
102 }
103
104private:
105 SoftwareRenderer *mTarget;
106
107 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
108 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
109};
110
111struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
112 AwesomeNativeWindowRenderer(
113 const sp<ANativeWindow> &nativeWindow,
114 int32_t rotationDegrees)
115 : mNativeWindow(nativeWindow) {
116 applyRotation(rotationDegrees);
117 }
118
119 virtual void render(MediaBuffer *buffer) {
120 status_t err = mNativeWindow->queueBuffer(
121 mNativeWindow.get(), buffer->graphicBuffer().get());
122 if (err != 0) {
Steve Blockf8bd29c2012-01-08 10:14:44 +0000123 ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
James Dongc9dedc42011-05-01 12:36:22 -0700124 -err);
125 return;
126 }
127
128 sp<MetaData> metaData = buffer->meta_data();
129 metaData->setInt32(kKeyRendered, 1);
130 }
131
132protected:
133 virtual ~AwesomeNativeWindowRenderer() {}
134
135private:
136 sp<ANativeWindow> mNativeWindow;
137
138 void applyRotation(int32_t rotationDegrees) {
139 uint32_t transform;
140 switch (rotationDegrees) {
141 case 0: transform = 0; break;
142 case 90: transform = HAL_TRANSFORM_ROT_90; break;
143 case 180: transform = HAL_TRANSFORM_ROT_180; break;
144 case 270: transform = HAL_TRANSFORM_ROT_270; break;
145 default: transform = 0; break;
146 }
147
148 if (transform) {
149 CHECK_EQ(0, native_window_set_buffers_transform(
150 mNativeWindow.get(), transform));
151 }
152 }
153
154 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
155 AwesomeNativeWindowRenderer &operator=(
156 const AwesomeNativeWindowRenderer &);
157};
158
159// To collect the decoder usage
160void addBatteryData(uint32_t params) {
161 sp<IBinder> binder =
162 defaultServiceManager()->getService(String16("media.player"));
163 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
164 CHECK(service.get() != NULL);
165
166 service->addBatteryData(params);
167}
168
169////////////////////////////////////////////////////////////////////////////////
170PreviewPlayerBase::PreviewPlayerBase()
171 : mQueueStarted(false),
172 mTimeSource(NULL),
173 mVideoRendererIsPreview(false),
174 mAudioPlayer(NULL),
175 mDisplayWidth(0),
176 mDisplayHeight(0),
177 mFlags(0),
178 mExtractorFlags(0),
179 mVideoBuffer(NULL),
James Dongc9dedc42011-05-01 12:36:22 -0700180 mLastVideoTimeUs(-1) {
181 CHECK_EQ(mClient.connect(), (status_t)OK);
182
183 DataSource::RegisterDefaultSniffers();
184
185 mVideoEvent = new AwesomeEvent(this, &PreviewPlayerBase::onVideoEvent);
186 mVideoEventPending = false;
187 mStreamDoneEvent = new AwesomeEvent(this, &PreviewPlayerBase::onStreamDone);
188 mStreamDoneEventPending = false;
189 mBufferingEvent = new AwesomeEvent(this, &PreviewPlayerBase::onBufferingUpdate);
190 mBufferingEventPending = false;
191 mVideoLagEvent = new AwesomeEvent(this, &PreviewPlayerBase::onVideoLagUpdate);
192 mVideoEventPending = false;
193
194 mCheckAudioStatusEvent = new AwesomeEvent(
195 this, &PreviewPlayerBase::onCheckAudioStatus);
196
197 mAudioStatusEventPending = false;
198
199 reset();
200}
201
202PreviewPlayerBase::~PreviewPlayerBase() {
203 if (mQueueStarted) {
204 mQueue.stop();
205 }
206
207 reset();
208
209 mClient.disconnect();
210}
211
212void PreviewPlayerBase::cancelPlayerEvents(bool keepBufferingGoing) {
213 mQueue.cancelEvent(mVideoEvent->eventID());
214 mVideoEventPending = false;
215 mQueue.cancelEvent(mStreamDoneEvent->eventID());
216 mStreamDoneEventPending = false;
217 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
218 mAudioStatusEventPending = false;
219 mQueue.cancelEvent(mVideoLagEvent->eventID());
220 mVideoLagEventPending = false;
221
222 if (!keepBufferingGoing) {
223 mQueue.cancelEvent(mBufferingEvent->eventID());
224 mBufferingEventPending = false;
225 }
226}
227
228void PreviewPlayerBase::setListener(const wp<MediaPlayerBase> &listener) {
229 Mutex::Autolock autoLock(mLock);
230 mListener = listener;
231}
232
233status_t PreviewPlayerBase::setDataSource(
234 const char *uri, const KeyedVector<String8, String8> *headers) {
235 Mutex::Autolock autoLock(mLock);
236 return setDataSource_l(uri, headers);
237}
238
239status_t PreviewPlayerBase::setDataSource_l(
240 const char *uri, const KeyedVector<String8, String8> *headers) {
241 reset_l();
242
243 mUri = uri;
244
245 if (headers) {
246 mUriHeaders = *headers;
247
248 ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
249 if (index >= 0) {
250 // Browser is in "incognito" mode, suppress logging URLs.
251
252 // This isn't something that should be passed to the server.
253 mUriHeaders.removeItemsAt(index);
254
255 mFlags |= INCOGNITO;
256 }
257 }
258
259 if (!(mFlags & INCOGNITO)) {
Steve Blockec9e6632012-01-04 20:06:05 +0000260 ALOGI("setDataSource_l('%s')", mUri.string());
James Dongc9dedc42011-05-01 12:36:22 -0700261 } else {
Steve Blockec9e6632012-01-04 20:06:05 +0000262 ALOGI("setDataSource_l(URL suppressed)");
James Dongc9dedc42011-05-01 12:36:22 -0700263 }
264
265 // The actual work will be done during preparation in the call to
266 // ::finishSetDataSource_l to avoid blocking the calling thread in
267 // setDataSource for any significant time.
268
269 return OK;
270}
271
272status_t PreviewPlayerBase::setDataSource(
273 int fd, int64_t offset, int64_t length) {
274 Mutex::Autolock autoLock(mLock);
275
276 reset_l();
277
278 sp<DataSource> dataSource = new FileSource(fd, offset, length);
279
280 status_t err = dataSource->initCheck();
281
282 if (err != OK) {
283 return err;
284 }
285
286 mFileSource = dataSource;
287
288 return setDataSource_l(dataSource);
289}
290
291status_t PreviewPlayerBase::setDataSource(const sp<IStreamSource> &source) {
292 return INVALID_OPERATION;
293}
294
295status_t PreviewPlayerBase::setDataSource_l(
296 const sp<DataSource> &dataSource) {
James Dongc0f8fbe2012-01-11 19:11:31 -0800297
James Dongc9dedc42011-05-01 12:36:22 -0700298 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
James Dongc9dedc42011-05-01 12:36:22 -0700299 return setDataSource_l(extractor);
300}
301
302status_t PreviewPlayerBase::setDataSource_l(const sp<MediaExtractor> &extractor) {
James Dongc0f8fbe2012-01-11 19:11:31 -0800303 if (extractor == NULL) {
304 return UNKNOWN_ERROR;
305 }
306
307 if (extractor->getDrmFlag()) {
308 ALOGE("Data source is drm protected");
309 return INVALID_OPERATION;
310 }
311
James Dongc9dedc42011-05-01 12:36:22 -0700312 // Attempt to approximate overall stream bitrate by summing all
313 // tracks' individual bitrates, if not all of them advertise bitrate,
314 // we have to fail.
315
316 int64_t totalBitRate = 0;
317
318 for (size_t i = 0; i < extractor->countTracks(); ++i) {
319 sp<MetaData> meta = extractor->getTrackMetaData(i);
320
321 int32_t bitrate;
322 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
323 totalBitRate = -1;
324 break;
325 }
326
327 totalBitRate += bitrate;
328 }
329
330 mBitrate = totalBitRate;
331
Steve Block2703f232011-10-20 11:56:09 +0100332 ALOGV("mBitrate = %lld bits/sec", mBitrate);
James Dongc9dedc42011-05-01 12:36:22 -0700333
334 bool haveAudio = false;
335 bool haveVideo = false;
336 for (size_t i = 0; i < extractor->countTracks(); ++i) {
337 sp<MetaData> meta = extractor->getTrackMetaData(i);
338
339 const char *mime;
340 CHECK(meta->findCString(kKeyMIMEType, &mime));
341
342 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
343 setVideoSource(extractor->getTrack(i));
344 haveVideo = true;
345
346 // Set the presentation/display size
347 int32_t displayWidth, displayHeight;
348 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
349 if (success) {
350 success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
351 }
352 if (success) {
353 mDisplayWidth = displayWidth;
354 mDisplayHeight = displayHeight;
355 }
356
357 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
358 setAudioSource(extractor->getTrack(i));
359 haveAudio = true;
360
361 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
362 // Only do this for vorbis audio, none of the other audio
363 // formats even support this ringtone specific hack and
364 // retrieving the metadata on some extractors may turn out
365 // to be very expensive.
366 sp<MetaData> fileMeta = extractor->getMetaData();
367 int32_t loop;
368 if (fileMeta != NULL
369 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
370 mFlags |= AUTO_LOOPING;
371 }
372 }
373 }
374
375 if (haveAudio && haveVideo) {
376 break;
377 }
378 }
379
380 if (!haveAudio && !haveVideo) {
381 return UNKNOWN_ERROR;
382 }
383
384 mExtractorFlags = extractor->flags();
385
386 return OK;
387}
388
389void PreviewPlayerBase::reset() {
390 Mutex::Autolock autoLock(mLock);
391 reset_l();
392}
393
394void PreviewPlayerBase::reset_l() {
395 mDisplayWidth = 0;
396 mDisplayHeight = 0;
397
James Dongc9dedc42011-05-01 12:36:22 -0700398 if (mFlags & PLAYING) {
399 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
400 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
401 params |= IMediaPlayerService::kBatteryDataTrackAudio;
402 }
403 if (mVideoSource != NULL) {
404 params |= IMediaPlayerService::kBatteryDataTrackVideo;
405 }
406 addBatteryData(params);
407 }
408
409 if (mFlags & PREPARING) {
410 mFlags |= PREPARE_CANCELLED;
411 if (mConnectingDataSource != NULL) {
Steve Blockec9e6632012-01-04 20:06:05 +0000412 ALOGI("interrupting the connection process");
James Dongc9dedc42011-05-01 12:36:22 -0700413 mConnectingDataSource->disconnect();
James Dongc9dedc42011-05-01 12:36:22 -0700414 }
415
416 if (mFlags & PREPARING_CONNECTED) {
417 // We are basically done preparing, we're just buffering
418 // enough data to start playback, we can safely interrupt that.
419 finishAsyncPrepare_l();
420 }
421 }
422
423 while (mFlags & PREPARING) {
424 mPreparedCondition.wait(mLock);
425 }
426
427 cancelPlayerEvents();
428
429 mCachedSource.clear();
430 mAudioTrack.clear();
431 mVideoTrack.clear();
432
433 // Shutdown audio first, so that the respone to the reset request
434 // appears to happen instantaneously as far as the user is concerned
435 // If we did this later, audio would continue playing while we
436 // shutdown the video-related resources and the player appear to
437 // not be as responsive to a reset request.
438 if (mAudioPlayer == NULL && mAudioSource != NULL) {
439 // If we had an audio player, it would have effectively
440 // taken possession of the audio source and stopped it when
441 // _it_ is stopped. Otherwise this is still our responsibility.
442 mAudioSource->stop();
443 }
444 mAudioSource.clear();
445
446 mTimeSource = NULL;
447
448 delete mAudioPlayer;
449 mAudioPlayer = NULL;
450
451 mVideoRenderer.clear();
452
James Dongc9dedc42011-05-01 12:36:22 -0700453 if (mVideoSource != NULL) {
454 shutdownVideoDecoder_l();
455 }
456
457 mDurationUs = -1;
458 mFlags = 0;
459 mExtractorFlags = 0;
460 mTimeSourceDeltaUs = 0;
461 mVideoTimeUs = 0;
462
463 mSeeking = NO_SEEK;
464 mSeekNotificationSent = false;
465 mSeekTimeUs = 0;
466
467 mUri.setTo("");
468 mUriHeaders.clear();
469
470 mFileSource.clear();
471
472 mBitrate = -1;
473 mLastVideoTimeUs = -1;
474}
475
476void PreviewPlayerBase::notifyListener_l(int msg, int ext1, int ext2) {
477 if (mListener != NULL) {
478 sp<MediaPlayerBase> listener = mListener.promote();
479
480 if (listener != NULL) {
481 listener->sendEvent(msg, ext1, ext2);
482 }
483 }
484}
485
486bool PreviewPlayerBase::getBitrate(int64_t *bitrate) {
487 off64_t size;
488 if (mDurationUs >= 0 && mCachedSource != NULL
489 && mCachedSource->getSize(&size) == OK) {
490 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
491 return true;
492 }
493
494 if (mBitrate >= 0) {
495 *bitrate = mBitrate;
496 return true;
497 }
498
499 *bitrate = 0;
500
501 return false;
502}
503
504// Returns true iff cached duration is available/applicable.
505bool PreviewPlayerBase::getCachedDuration_l(int64_t *durationUs, bool *eos) {
506 int64_t bitrate;
507
Andreas Huber4a4a8f02011-10-12 15:08:42 -0700508 if (mCachedSource != NULL && getBitrate(&bitrate)) {
James Dongc9dedc42011-05-01 12:36:22 -0700509 status_t finalStatus;
510 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
511 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
512 *eos = (finalStatus != OK);
513 return true;
514 }
515
516 return false;
517}
518
519void PreviewPlayerBase::ensureCacheIsFetching_l() {
520 if (mCachedSource != NULL) {
521 mCachedSource->resumeFetchingIfNecessary();
522 }
523}
524
525void PreviewPlayerBase::onVideoLagUpdate() {
526 Mutex::Autolock autoLock(mLock);
527 if (!mVideoLagEventPending) {
528 return;
529 }
530 mVideoLagEventPending = false;
531
532 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
533 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
534
535 if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
Steve Block2703f232011-10-20 11:56:09 +0100536 ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
James Dongc9dedc42011-05-01 12:36:22 -0700537
538 notifyListener_l(
539 MEDIA_INFO,
540 MEDIA_INFO_VIDEO_TRACK_LAGGING,
541 videoLateByUs / 1000ll);
542 }
543
544 postVideoLagEvent_l();
545}
546
547void PreviewPlayerBase::onBufferingUpdate() {
548 Mutex::Autolock autoLock(mLock);
549 if (!mBufferingEventPending) {
550 return;
551 }
552 mBufferingEventPending = false;
553
554 if (mCachedSource != NULL) {
555 status_t finalStatus;
556 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
557 bool eos = (finalStatus != OK);
558
559 if (eos) {
560 if (finalStatus == ERROR_END_OF_STREAM) {
561 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
562 }
563 if (mFlags & PREPARING) {
Steve Block2703f232011-10-20 11:56:09 +0100564 ALOGV("cache has reached EOS, prepare is done.");
James Dongc9dedc42011-05-01 12:36:22 -0700565 finishAsyncPrepare_l();
566 }
567 } else {
568 int64_t bitrate;
569 if (getBitrate(&bitrate)) {
570 size_t cachedSize = mCachedSource->cachedSize();
571 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
572
573 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
574 if (percentage > 100) {
575 percentage = 100;
576 }
577
578 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
579 } else {
580 // We don't know the bitrate of the stream, use absolute size
581 // limits to maintain the cache.
582
583 if ((mFlags & PLAYING) && !eos
584 && (cachedDataRemaining < kLowWaterMarkBytes)) {
Steve Blockec9e6632012-01-04 20:06:05 +0000585 ALOGI("cache is running low (< %d) , pausing.",
James Dongc9dedc42011-05-01 12:36:22 -0700586 kLowWaterMarkBytes);
587 mFlags |= CACHE_UNDERRUN;
588 pause_l();
589 ensureCacheIsFetching_l();
590 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
591 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
592 if (mFlags & CACHE_UNDERRUN) {
Steve Blockec9e6632012-01-04 20:06:05 +0000593 ALOGI("cache has filled up (> %d), resuming.",
James Dongc9dedc42011-05-01 12:36:22 -0700594 kHighWaterMarkBytes);
595 mFlags &= ~CACHE_UNDERRUN;
596 play_l();
597 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
598 } else if (mFlags & PREPARING) {
Steve Block2703f232011-10-20 11:56:09 +0100599 ALOGV("cache has filled up (> %d), prepare is done",
James Dongc9dedc42011-05-01 12:36:22 -0700600 kHighWaterMarkBytes);
601 finishAsyncPrepare_l();
602 }
603 }
604 }
605 }
606 }
607
608 int64_t cachedDurationUs;
609 bool eos;
610 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Steve Block2703f232011-10-20 11:56:09 +0100611 ALOGV("cachedDurationUs = %.2f secs, eos=%d",
James Dongc9dedc42011-05-01 12:36:22 -0700612 cachedDurationUs / 1E6, eos);
613
James Dongc9dedc42011-05-01 12:36:22 -0700614 if ((mFlags & PLAYING) && !eos
615 && (cachedDurationUs < kLowWaterMarkUs)) {
Steve Blockec9e6632012-01-04 20:06:05 +0000616 ALOGI("cache is running low (%.2f secs) , pausing.",
James Dongc9dedc42011-05-01 12:36:22 -0700617 cachedDurationUs / 1E6);
618 mFlags |= CACHE_UNDERRUN;
619 pause_l();
620 ensureCacheIsFetching_l();
621 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber4a4a8f02011-10-12 15:08:42 -0700622 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
James Dongc9dedc42011-05-01 12:36:22 -0700623 if (mFlags & CACHE_UNDERRUN) {
Steve Blockec9e6632012-01-04 20:06:05 +0000624 ALOGI("cache has filled up (%.2f secs), resuming.",
James Dongc9dedc42011-05-01 12:36:22 -0700625 cachedDurationUs / 1E6);
626 mFlags &= ~CACHE_UNDERRUN;
627 play_l();
628 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
629 } else if (mFlags & PREPARING) {
Steve Block2703f232011-10-20 11:56:09 +0100630 ALOGV("cache has filled up (%.2f secs), prepare is done",
James Dongc9dedc42011-05-01 12:36:22 -0700631 cachedDurationUs / 1E6);
632 finishAsyncPrepare_l();
633 }
634 }
635 }
636
637 postBufferingEvent_l();
638}
639
640void PreviewPlayerBase::onStreamDone() {
641 // Posted whenever any stream finishes playing.
642
643 Mutex::Autolock autoLock(mLock);
644 if (!mStreamDoneEventPending) {
645 return;
646 }
647 mStreamDoneEventPending = false;
648
649 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Steve Block2703f232011-10-20 11:56:09 +0100650 ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
James Dongc9dedc42011-05-01 12:36:22 -0700651
652 notifyListener_l(
653 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
654
655 pause_l(true /* at eos */);
656
657 mFlags |= AT_EOS;
658 return;
659 }
660
661 const bool allDone =
662 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
663 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
664
665 if (!allDone) {
666 return;
667 }
668
669 if (mFlags & (LOOPING | AUTO_LOOPING)) {
670 seekTo_l(0);
671
672 if (mVideoSource != NULL) {
673 postVideoEvent_l();
674 }
675 } else {
Steve Block2703f232011-10-20 11:56:09 +0100676 ALOGV("MEDIA_PLAYBACK_COMPLETE");
James Dongc9dedc42011-05-01 12:36:22 -0700677 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
678
679 pause_l(true /* at eos */);
680
681 mFlags |= AT_EOS;
682 }
683}
684
685status_t PreviewPlayerBase::play() {
686 Mutex::Autolock autoLock(mLock);
687
688 mFlags &= ~CACHE_UNDERRUN;
689
690 return play_l();
691}
692
693status_t PreviewPlayerBase::play_l() {
694 mFlags &= ~SEEK_PREVIEW;
695
696 if (mFlags & PLAYING) {
697 return OK;
698 }
699
700 if (!(mFlags & PREPARED)) {
701 status_t err = prepare_l();
702
703 if (err != OK) {
704 return err;
705 }
706 }
707
708 mFlags |= PLAYING;
709 mFlags |= FIRST_FRAME;
710
James Dongc9dedc42011-05-01 12:36:22 -0700711 if (mAudioSource != NULL) {
712 if (mAudioPlayer == NULL) {
713 if (mAudioSink != NULL) {
714 mAudioPlayer = new AudioPlayerBase(mAudioSink, this);
715 mAudioPlayer->setSource(mAudioSource);
716
717 mTimeSource = mAudioPlayer;
718
719 // If there was a seek request before we ever started,
720 // honor the request now.
721 // Make sure to do this before starting the audio player
722 // to avoid a race condition.
723 seekAudioIfNecessary_l();
724 }
725 }
726
727 CHECK(!(mFlags & AUDIO_RUNNING));
728
729 if (mVideoSource == NULL) {
730 status_t err = startAudioPlayer_l();
731
732 if (err != OK) {
733 delete mAudioPlayer;
734 mAudioPlayer = NULL;
735
736 mFlags &= ~(PLAYING | FIRST_FRAME);
737
James Dongc9dedc42011-05-01 12:36:22 -0700738 return err;
739 }
740 }
741 }
742
743 if (mTimeSource == NULL && mAudioPlayer == NULL) {
744 mTimeSource = &mSystemTimeSource;
745 }
746
747 if (mVideoSource != NULL) {
748 // Kick off video playback
749 postVideoEvent_l();
750
751 if (mAudioSource != NULL && mVideoSource != NULL) {
752 postVideoLagEvent_l();
753 }
754 }
755
756 if (mFlags & AT_EOS) {
757 // Legacy behaviour, if a stream finishes playing and then
758 // is started again, we play from the start...
759 seekTo_l(0);
760 }
761
762 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
763 | IMediaPlayerService::kBatteryDataTrackDecoder;
764 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
765 params |= IMediaPlayerService::kBatteryDataTrackAudio;
766 }
767 if (mVideoSource != NULL) {
768 params |= IMediaPlayerService::kBatteryDataTrackVideo;
769 }
770 addBatteryData(params);
771
772 return OK;
773}
774
775status_t PreviewPlayerBase::startAudioPlayer_l() {
776 CHECK(!(mFlags & AUDIO_RUNNING));
777
778 if (mAudioSource == NULL || mAudioPlayer == NULL) {
779 return OK;
780 }
781
782 if (!(mFlags & AUDIOPLAYER_STARTED)) {
783 mFlags |= AUDIOPLAYER_STARTED;
784
785 // We've already started the MediaSource in order to enable
786 // the prefetcher to read its data.
787 status_t err = mAudioPlayer->start(
788 true /* sourceAlreadyStarted */);
789
790 if (err != OK) {
791 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
792 return err;
793 }
794 } else {
795 mAudioPlayer->resume();
796 }
797
798 mFlags |= AUDIO_RUNNING;
799
800 mWatchForAudioEOS = true;
801
802 return OK;
803}
804
805void PreviewPlayerBase::notifyVideoSize_l() {
806 sp<MetaData> meta = mVideoSource->getFormat();
807
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800808 int32_t vWidth, vHeight;
James Dongc9dedc42011-05-01 12:36:22 -0700809 int32_t cropLeft, cropTop, cropRight, cropBottom;
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800810
811 CHECK(meta->findInt32(kKeyWidth, &vWidth));
812 CHECK(meta->findInt32(kKeyHeight, &vHeight));
813
814 mGivenWidth = vWidth;
815 mGivenHeight = vHeight;
816
James Dongc9dedc42011-05-01 12:36:22 -0700817 if (!meta->findRect(
818 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
James Dongc9dedc42011-05-01 12:36:22 -0700819
820 cropLeft = cropTop = 0;
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800821 cropRight = vWidth - 1;
822 cropBottom = vHeight - 1;
James Dongc9dedc42011-05-01 12:36:22 -0700823
Steve Block4ca06b02011-12-20 16:24:14 +0000824 ALOGD("got dimensions only %d x %d", vWidth, vHeight);
James Dongc9dedc42011-05-01 12:36:22 -0700825 } else {
Steve Block4ca06b02011-12-20 16:24:14 +0000826 ALOGD("got crop rect %d, %d, %d, %d",
James Dongc9dedc42011-05-01 12:36:22 -0700827 cropLeft, cropTop, cropRight, cropBottom);
828 }
829
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800830 mCropRect.left = cropLeft;
831 mCropRect.right = cropRight;
832 mCropRect.top = cropTop;
833 mCropRect.bottom = cropBottom;
834
James Dongc9dedc42011-05-01 12:36:22 -0700835 int32_t displayWidth;
836 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
Steve Block2703f232011-10-20 11:56:09 +0100837 ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
James Dongc9dedc42011-05-01 12:36:22 -0700838 mDisplayWidth = displayWidth;
839 }
840 int32_t displayHeight;
841 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
Steve Block2703f232011-10-20 11:56:09 +0100842 ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
James Dongc9dedc42011-05-01 12:36:22 -0700843 mDisplayHeight = displayHeight;
844 }
845
846 int32_t usableWidth = cropRight - cropLeft + 1;
847 int32_t usableHeight = cropBottom - cropTop + 1;
848 if (mDisplayWidth != 0) {
849 usableWidth = mDisplayWidth;
850 }
851 if (mDisplayHeight != 0) {
852 usableHeight = mDisplayHeight;
853 }
854
855 int32_t rotationDegrees;
856 if (!mVideoTrack->getFormat()->findInt32(
857 kKeyRotation, &rotationDegrees)) {
858 rotationDegrees = 0;
859 }
860
861 if (rotationDegrees == 90 || rotationDegrees == 270) {
862 notifyListener_l(
863 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
864 } else {
865 notifyListener_l(
866 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
867 }
868}
869
870void PreviewPlayerBase::initRenderer_l() {
871 if (mNativeWindow == NULL) {
872 return;
873 }
874
875 sp<MetaData> meta = mVideoSource->getFormat();
876
877 int32_t format;
878 const char *component;
James Dongc9dedc42011-05-01 12:36:22 -0700879 CHECK(meta->findInt32(kKeyColorFormat, &format));
880 CHECK(meta->findCString(kKeyDecoderComponent, &component));
James Dongc9dedc42011-05-01 12:36:22 -0700881
882 int32_t rotationDegrees;
883 if (!mVideoTrack->getFormat()->findInt32(
884 kKeyRotation, &rotationDegrees)) {
885 rotationDegrees = 0;
886 }
887
888 mVideoRenderer.clear();
889
890 // Must ensure that mVideoRenderer's destructor is actually executed
891 // before creating a new one.
892 IPCThreadState::self()->flushCommands();
893
894 if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
895 // Hardware decoders avoid the CPU color conversion by decoding
896 // directly to ANativeBuffers, so we must use a renderer that
897 // just pushes those buffers to the ANativeWindow.
898 mVideoRenderer =
899 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
900 } else {
901 // Other decoders are instantiated locally and as a consequence
902 // allocate their buffers in local address space. This renderer
903 // then performs a color conversion and copy to get the data
904 // into the ANativeBuffer.
905 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
906 }
907}
908
909status_t PreviewPlayerBase::pause() {
910 Mutex::Autolock autoLock(mLock);
911
912 mFlags &= ~CACHE_UNDERRUN;
913
914 return pause_l();
915}
916
917status_t PreviewPlayerBase::pause_l(bool at_eos) {
918 if (!(mFlags & PLAYING)) {
919 return OK;
920 }
921
922 cancelPlayerEvents(true /* keepBufferingGoing */);
923
924 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
925 if (at_eos) {
926 // If we played the audio stream to completion we
927 // want to make sure that all samples remaining in the audio
928 // track's queue are played out.
929 mAudioPlayer->pause(true /* playPendingSamples */);
930 } else {
931 mAudioPlayer->pause();
932 }
933
934 mFlags &= ~AUDIO_RUNNING;
935 }
936
937 mFlags &= ~PLAYING;
938
James Dongc9dedc42011-05-01 12:36:22 -0700939 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
940 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
941 params |= IMediaPlayerService::kBatteryDataTrackAudio;
942 }
943 if (mVideoSource != NULL) {
944 params |= IMediaPlayerService::kBatteryDataTrackVideo;
945 }
946
947 addBatteryData(params);
948
949 return OK;
950}
951
952bool PreviewPlayerBase::isPlaying() const {
953 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
954}
955
956void PreviewPlayerBase::setSurface(const sp<Surface> &surface) {
957 Mutex::Autolock autoLock(mLock);
958
959 mSurface = surface;
960 setNativeWindow_l(surface);
961}
962
963void PreviewPlayerBase::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
964 Mutex::Autolock autoLock(mLock);
965
966 mSurface.clear();
967 if (surfaceTexture != NULL) {
968 setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
969 }
970}
971
972void PreviewPlayerBase::shutdownVideoDecoder_l() {
973 if (mVideoBuffer) {
974 mVideoBuffer->release();
975 mVideoBuffer = NULL;
976 }
977
978 mVideoSource->stop();
979
980 // The following hack is necessary to ensure that the OMX
981 // component is completely released by the time we may try
982 // to instantiate it again.
983 wp<MediaSource> tmp = mVideoSource;
984 mVideoSource.clear();
985 while (tmp.promote() != NULL) {
986 usleep(1000);
987 }
988 IPCThreadState::self()->flushCommands();
989}
990
991void PreviewPlayerBase::setNativeWindow_l(const sp<ANativeWindow> &native) {
992 mNativeWindow = native;
993
994 if (mVideoSource == NULL) {
995 return;
996 }
997
Steve Blockec9e6632012-01-04 20:06:05 +0000998 ALOGI("attempting to reconfigure to use new surface");
James Dongc9dedc42011-05-01 12:36:22 -0700999
1000 bool wasPlaying = (mFlags & PLAYING) != 0;
1001
1002 pause_l();
1003 mVideoRenderer.clear();
1004
1005 shutdownVideoDecoder_l();
1006
1007 CHECK_EQ(initVideoDecoder(), (status_t)OK);
1008
1009 if (mLastVideoTimeUs >= 0) {
1010 mSeeking = SEEK;
1011 mSeekNotificationSent = true;
1012 mSeekTimeUs = mLastVideoTimeUs;
1013 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1014 }
1015
1016 if (wasPlaying) {
1017 play_l();
1018 }
1019}
1020
1021void PreviewPlayerBase::setAudioSink(
1022 const sp<MediaPlayerBase::AudioSink> &audioSink) {
1023 Mutex::Autolock autoLock(mLock);
1024
1025 mAudioSink = audioSink;
1026}
1027
1028status_t PreviewPlayerBase::setLooping(bool shouldLoop) {
1029 Mutex::Autolock autoLock(mLock);
1030
1031 mFlags = mFlags & ~LOOPING;
1032
1033 if (shouldLoop) {
1034 mFlags |= LOOPING;
1035 }
1036
1037 return OK;
1038}
1039
1040status_t PreviewPlayerBase::getDuration(int64_t *durationUs) {
1041 Mutex::Autolock autoLock(mMiscStateLock);
1042
1043 if (mDurationUs < 0) {
1044 return UNKNOWN_ERROR;
1045 }
1046
1047 *durationUs = mDurationUs;
1048
1049 return OK;
1050}
1051
1052status_t PreviewPlayerBase::getPosition(int64_t *positionUs) {
Andreas Huber4a4a8f02011-10-12 15:08:42 -07001053 if (mSeeking != NO_SEEK) {
James Dongc9dedc42011-05-01 12:36:22 -07001054 *positionUs = mSeekTimeUs;
1055 } else if (mVideoSource != NULL
1056 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
1057 Mutex::Autolock autoLock(mMiscStateLock);
1058 *positionUs = mVideoTimeUs;
1059 } else if (mAudioPlayer != NULL) {
1060 *positionUs = mAudioPlayer->getMediaTimeUs();
1061 } else {
1062 *positionUs = 0;
1063 }
1064
1065 return OK;
1066}
1067
1068status_t PreviewPlayerBase::seekTo(int64_t timeUs) {
1069 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
1070 Mutex::Autolock autoLock(mLock);
1071 return seekTo_l(timeUs);
1072 }
1073
1074 return OK;
1075}
1076
James Dongc9dedc42011-05-01 12:36:22 -07001077status_t PreviewPlayerBase::seekTo_l(int64_t timeUs) {
James Dongc9dedc42011-05-01 12:36:22 -07001078 if (mFlags & CACHE_UNDERRUN) {
1079 mFlags &= ~CACHE_UNDERRUN;
1080 play_l();
1081 }
1082
1083 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
1084 // Video playback completed before, there's no pending
1085 // video event right now. In order for this new seek
1086 // to be honored, we need to post one.
1087
1088 postVideoEvent_l();
1089 }
1090
1091 mSeeking = SEEK;
1092 mSeekNotificationSent = false;
1093 mSeekTimeUs = timeUs;
1094 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
1095
1096 seekAudioIfNecessary_l();
1097
1098 if (!(mFlags & PLAYING)) {
Steve Block2703f232011-10-20 11:56:09 +01001099 ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
James Dongc9dedc42011-05-01 12:36:22 -07001100 " immediately.");
1101
1102 notifyListener_l(MEDIA_SEEK_COMPLETE);
1103 mSeekNotificationSent = true;
1104
1105 if ((mFlags & PREPARED) && mVideoSource != NULL) {
1106 mFlags |= SEEK_PREVIEW;
1107 postVideoEvent_l();
1108 }
1109 }
1110
1111 return OK;
1112}
1113
1114void PreviewPlayerBase::seekAudioIfNecessary_l() {
1115 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
1116 mAudioPlayer->seekTo(mSeekTimeUs);
1117
1118 mWatchForAudioSeekComplete = true;
1119 mWatchForAudioEOS = true;
James Dongc9dedc42011-05-01 12:36:22 -07001120 }
1121}
1122
1123void PreviewPlayerBase::setAudioSource(sp<MediaSource> source) {
1124 CHECK(source != NULL);
1125
1126 mAudioTrack = source;
1127}
1128
1129status_t PreviewPlayerBase::initAudioDecoder() {
1130 sp<MetaData> meta = mAudioTrack->getFormat();
1131
1132 const char *mime;
1133 CHECK(meta->findCString(kKeyMIMEType, &mime));
1134
1135 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
1136 mAudioSource = mAudioTrack;
1137 } else {
1138 mAudioSource = OMXCodec::Create(
1139 mClient.interface(), mAudioTrack->getFormat(),
1140 false, // createEncoder
1141 mAudioTrack);
1142 }
1143
1144 if (mAudioSource != NULL) {
1145 int64_t durationUs;
1146 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1147 Mutex::Autolock autoLock(mMiscStateLock);
1148 if (mDurationUs < 0 || durationUs > mDurationUs) {
1149 mDurationUs = durationUs;
1150 }
1151 }
1152
1153 status_t err = mAudioSource->start();
1154
1155 if (err != OK) {
1156 mAudioSource.clear();
1157 return err;
1158 }
1159 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1160 // For legacy reasons we're simply going to ignore the absence
1161 // of an audio decoder for QCELP instead of aborting playback
1162 // altogether.
1163 return OK;
1164 }
1165
1166 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1167}
1168
1169void PreviewPlayerBase::setVideoSource(sp<MediaSource> source) {
1170 CHECK(source != NULL);
1171
1172 mVideoTrack = source;
1173}
1174
1175status_t PreviewPlayerBase::initVideoDecoder(uint32_t flags) {
Steve Block2703f232011-10-20 11:56:09 +01001176 ALOGV("initVideoDecoder flags=0x%x", flags);
James Dongc9dedc42011-05-01 12:36:22 -07001177 mVideoSource = OMXCodec::Create(
1178 mClient.interface(), mVideoTrack->getFormat(),
1179 false, // createEncoder
1180 mVideoTrack,
1181 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
1182
1183 if (mVideoSource != NULL) {
1184 int64_t durationUs;
1185 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
1186 Mutex::Autolock autoLock(mMiscStateLock);
1187 if (mDurationUs < 0 || durationUs > mDurationUs) {
1188 mDurationUs = durationUs;
1189 }
1190 }
1191
1192 status_t err = mVideoSource->start();
1193
1194 if (err != OK) {
1195 mVideoSource.clear();
1196 return err;
1197 }
1198 }
1199
1200 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1201}
1202
1203void PreviewPlayerBase::finishSeekIfNecessary(int64_t videoTimeUs) {
1204 if (mSeeking == SEEK_VIDEO_ONLY) {
1205 mSeeking = NO_SEEK;
1206 return;
1207 }
1208
1209 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1210 return;
1211 }
1212
1213 if (mAudioPlayer != NULL) {
Steve Block2703f232011-10-20 11:56:09 +01001214 ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001215
1216 // If we don't have a video time, seek audio to the originally
1217 // requested seek time instead.
1218
1219 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1220 mWatchForAudioSeekComplete = true;
1221 mWatchForAudioEOS = true;
1222 } else if (!mSeekNotificationSent) {
1223 // If we're playing video only, report seek complete now,
1224 // otherwise audio player will notify us later.
1225 notifyListener_l(MEDIA_SEEK_COMPLETE);
1226 mSeekNotificationSent = true;
1227 }
1228
1229 mFlags |= FIRST_FRAME;
1230 mSeeking = NO_SEEK;
James Dongc9dedc42011-05-01 12:36:22 -07001231}
1232
1233void PreviewPlayerBase::onVideoEvent() {
1234 Mutex::Autolock autoLock(mLock);
1235 if (!mVideoEventPending) {
1236 // The event has been cancelled in reset_l() but had already
1237 // been scheduled for execution at that time.
1238 return;
1239 }
1240 mVideoEventPending = false;
1241
1242 if (mSeeking != NO_SEEK) {
1243 if (mVideoBuffer) {
1244 mVideoBuffer->release();
1245 mVideoBuffer = NULL;
1246 }
1247
1248 if (mSeeking == SEEK && mCachedSource != NULL && mAudioSource != NULL
1249 && !(mFlags & SEEK_PREVIEW)) {
1250 // We're going to seek the video source first, followed by
1251 // the audio source.
1252 // In order to avoid jumps in the DataSource offset caused by
1253 // the audio codec prefetching data from the old locations
1254 // while the video codec is already reading data from the new
1255 // locations, we'll "pause" the audio source, causing it to
1256 // stop reading input data until a subsequent seek.
1257
1258 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
1259 mAudioPlayer->pause();
1260
1261 mFlags &= ~AUDIO_RUNNING;
1262 }
1263 mAudioSource->pause();
1264 }
1265 }
1266
1267 if (!mVideoBuffer) {
1268 MediaSource::ReadOptions options;
1269 if (mSeeking != NO_SEEK) {
Steve Block2703f232011-10-20 11:56:09 +01001270 ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001271
1272 options.setSeekTo(
1273 mSeekTimeUs,
1274 mSeeking == SEEK_VIDEO_ONLY
1275 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
1276 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1277 }
1278 for (;;) {
Chih-Chung Chang43fcc392011-08-02 16:17:39 +08001279 status_t err = mVideoSource->read(&mVideoBuffer, &options);
James Dongc9dedc42011-05-01 12:36:22 -07001280 options.clearSeekTo();
1281
1282 if (err != OK) {
1283 CHECK(mVideoBuffer == NULL);
1284
1285 if (err == INFO_FORMAT_CHANGED) {
Steve Block2703f232011-10-20 11:56:09 +01001286 ALOGV("VideoSource signalled format change.");
James Dongc9dedc42011-05-01 12:36:22 -07001287
1288 notifyVideoSize_l();
1289
1290 if (mVideoRenderer != NULL) {
1291 mVideoRendererIsPreview = false;
1292 initRenderer_l();
1293 }
1294 continue;
1295 }
1296
1297 // So video playback is complete, but we may still have
1298 // a seek request pending that needs to be applied
1299 // to the audio track.
1300 if (mSeeking != NO_SEEK) {
Steve Block2703f232011-10-20 11:56:09 +01001301 ALOGV("video stream ended while seeking!");
James Dongc9dedc42011-05-01 12:36:22 -07001302 }
1303 finishSeekIfNecessary(-1);
1304
1305 if (mAudioPlayer != NULL
1306 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1307 startAudioPlayer_l();
1308 }
1309
1310 mFlags |= VIDEO_AT_EOS;
1311 postStreamDoneEvent_l(err);
1312 return;
1313 }
1314
1315 if (mVideoBuffer->range_length() == 0) {
1316 // Some decoders, notably the PV AVC software decoder
1317 // return spurious empty buffers that we just want to ignore.
1318
1319 mVideoBuffer->release();
1320 mVideoBuffer = NULL;
1321 continue;
1322 }
1323
1324 break;
1325 }
1326 }
1327
1328 int64_t timeUs;
1329 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1330
1331 mLastVideoTimeUs = timeUs;
1332
1333 if (mSeeking == SEEK_VIDEO_ONLY) {
1334 if (mSeekTimeUs > timeUs) {
Steve Blockec9e6632012-01-04 20:06:05 +00001335 ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
James Dongc9dedc42011-05-01 12:36:22 -07001336 mSeekTimeUs, timeUs);
1337 }
1338 }
1339
1340 {
1341 Mutex::Autolock autoLock(mMiscStateLock);
1342 mVideoTimeUs = timeUs;
1343 }
1344
1345 SeekType wasSeeking = mSeeking;
1346 finishSeekIfNecessary(timeUs);
1347
1348 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1349 status_t err = startAudioPlayer_l();
1350 if (err != OK) {
Steve Blockf8bd29c2012-01-08 10:14:44 +00001351 ALOGE("Startung the audio player failed w/ err %d", err);
James Dongc9dedc42011-05-01 12:36:22 -07001352 return;
1353 }
1354 }
1355
1356 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1357
1358 if (mFlags & FIRST_FRAME) {
1359 mFlags &= ~FIRST_FRAME;
1360 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1361 }
1362
1363 int64_t realTimeUs, mediaTimeUs;
1364 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1365 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1366 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1367 }
1368
1369 if (wasSeeking == SEEK_VIDEO_ONLY) {
1370 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1371
1372 int64_t latenessUs = nowUs - timeUs;
1373
1374 if (latenessUs > 0) {
Steve Blockec9e6632012-01-04 20:06:05 +00001375 ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001376 }
1377 }
1378
1379 if (wasSeeking == NO_SEEK) {
1380 // Let's display the first frame after seeking right away.
1381
1382 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1383
1384 int64_t latenessUs = nowUs - timeUs;
1385
1386 if (latenessUs > 500000ll
James Dongc9dedc42011-05-01 12:36:22 -07001387 && mAudioPlayer != NULL
1388 && mAudioPlayer->getMediaTimeMapping(
1389 &realTimeUs, &mediaTimeUs)) {
Steve Blockec9e6632012-01-04 20:06:05 +00001390 ALOGI("we're much too late (%.2f secs), video skipping ahead",
James Dongc9dedc42011-05-01 12:36:22 -07001391 latenessUs / 1E6);
1392
1393 mVideoBuffer->release();
1394 mVideoBuffer = NULL;
1395
1396 mSeeking = SEEK_VIDEO_ONLY;
1397 mSeekTimeUs = mediaTimeUs;
1398
1399 postVideoEvent_l();
1400 return;
1401 }
1402
1403 if (latenessUs > 40000) {
1404 // We're more than 40ms late.
Steve Block2703f232011-10-20 11:56:09 +01001405 ALOGV("we're late by %lld us (%.2f secs), dropping frame",
James Dongc9dedc42011-05-01 12:36:22 -07001406 latenessUs, latenessUs / 1E6);
1407 mVideoBuffer->release();
1408 mVideoBuffer = NULL;
1409
1410 postVideoEvent_l();
1411 return;
1412 }
1413
1414 if (latenessUs < -10000) {
1415 // We're more than 10ms early.
1416
1417 postVideoEvent_l(10000);
1418 return;
1419 }
1420 }
1421
1422 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1423 mVideoRendererIsPreview = false;
1424
1425 initRenderer_l();
1426 }
1427
1428 if (mVideoRenderer != NULL) {
1429 mVideoRenderer->render(mVideoBuffer);
1430 }
1431
1432 mVideoBuffer->release();
1433 mVideoBuffer = NULL;
1434
1435 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
1436 mFlags &= ~SEEK_PREVIEW;
1437 return;
1438 }
1439
1440 postVideoEvent_l();
1441}
1442
1443void PreviewPlayerBase::postVideoEvent_l(int64_t delayUs) {
1444 if (mVideoEventPending) {
1445 return;
1446 }
1447
1448 mVideoEventPending = true;
1449 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1450}
1451
1452void PreviewPlayerBase::postStreamDoneEvent_l(status_t status) {
1453 if (mStreamDoneEventPending) {
1454 return;
1455 }
1456 mStreamDoneEventPending = true;
1457
1458 mStreamDoneStatus = status;
1459 mQueue.postEvent(mStreamDoneEvent);
1460}
1461
1462void PreviewPlayerBase::postBufferingEvent_l() {
1463 if (mBufferingEventPending) {
1464 return;
1465 }
1466 mBufferingEventPending = true;
1467 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1468}
1469
1470void PreviewPlayerBase::postVideoLagEvent_l() {
1471 if (mVideoLagEventPending) {
1472 return;
1473 }
1474 mVideoLagEventPending = true;
1475 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
1476}
1477
1478void PreviewPlayerBase::postCheckAudioStatusEvent_l(int64_t delayUs) {
1479 if (mAudioStatusEventPending) {
1480 return;
1481 }
1482 mAudioStatusEventPending = true;
1483 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
1484}
1485
1486void PreviewPlayerBase::onCheckAudioStatus() {
1487 Mutex::Autolock autoLock(mLock);
1488 if (!mAudioStatusEventPending) {
1489 // Event was dispatched and while we were blocking on the mutex,
1490 // has already been cancelled.
1491 return;
1492 }
1493
1494 mAudioStatusEventPending = false;
1495
1496 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1497 mWatchForAudioSeekComplete = false;
1498
1499 if (!mSeekNotificationSent) {
1500 notifyListener_l(MEDIA_SEEK_COMPLETE);
1501 mSeekNotificationSent = true;
1502 }
1503
1504 mSeeking = NO_SEEK;
1505 }
1506
1507 status_t finalStatus;
1508 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
1509 mWatchForAudioEOS = false;
1510 mFlags |= AUDIO_AT_EOS;
1511 mFlags |= FIRST_FRAME;
1512 postStreamDoneEvent_l(finalStatus);
1513 }
1514}
1515
1516status_t PreviewPlayerBase::prepare() {
1517 Mutex::Autolock autoLock(mLock);
1518 return prepare_l();
1519}
1520
1521status_t PreviewPlayerBase::prepare_l() {
1522 if (mFlags & PREPARED) {
1523 return OK;
1524 }
1525
1526 if (mFlags & PREPARING) {
1527 return UNKNOWN_ERROR;
1528 }
1529
1530 mIsAsyncPrepare = false;
1531 status_t err = prepareAsync_l();
1532
1533 if (err != OK) {
1534 return err;
1535 }
1536
1537 while (mFlags & PREPARING) {
1538 mPreparedCondition.wait(mLock);
1539 }
1540
1541 return mPrepareResult;
1542}
1543
1544status_t PreviewPlayerBase::prepareAsync() {
1545 Mutex::Autolock autoLock(mLock);
1546
1547 if (mFlags & PREPARING) {
1548 return UNKNOWN_ERROR; // async prepare already pending
1549 }
1550
1551 mIsAsyncPrepare = true;
1552 return prepareAsync_l();
1553}
1554
1555status_t PreviewPlayerBase::prepareAsync_l() {
1556 if (mFlags & PREPARING) {
1557 return UNKNOWN_ERROR; // async prepare already pending
1558 }
1559
1560 if (!mQueueStarted) {
1561 mQueue.start();
1562 mQueueStarted = true;
1563 }
1564
1565 mFlags |= PREPARING;
1566 mAsyncPrepareEvent = new AwesomeEvent(
1567 this, &PreviewPlayerBase::onPrepareAsyncEvent);
1568
1569 mQueue.postEvent(mAsyncPrepareEvent);
1570
1571 return OK;
1572}
1573
1574status_t PreviewPlayerBase::finishSetDataSource_l() {
James Dongc0f8fbe2012-01-11 19:11:31 -08001575 sp<DataSource> dataSource =
1576 DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
James Dongc9dedc42011-05-01 12:36:22 -07001577
1578 if (dataSource == NULL) {
1579 return UNKNOWN_ERROR;
1580 }
1581
1582 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1583
James Dongc9dedc42011-05-01 12:36:22 -07001584 return setDataSource_l(extractor);
1585}
1586
1587void PreviewPlayerBase::abortPrepare(status_t err) {
1588 CHECK(err != OK);
1589
1590 if (mIsAsyncPrepare) {
1591 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1592 }
1593
1594 mPrepareResult = err;
1595 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1596 mAsyncPrepareEvent = NULL;
1597 mPreparedCondition.broadcast();
1598}
1599
1600// static
1601bool PreviewPlayerBase::ContinuePreparation(void *cookie) {
1602 PreviewPlayerBase *me = static_cast<PreviewPlayerBase *>(cookie);
1603
1604 return (me->mFlags & PREPARE_CANCELLED) == 0;
1605}
1606
1607void PreviewPlayerBase::onPrepareAsyncEvent() {
1608 Mutex::Autolock autoLock(mLock);
1609
1610 if (mFlags & PREPARE_CANCELLED) {
Steve Blockec9e6632012-01-04 20:06:05 +00001611 ALOGI("prepare was cancelled before doing anything");
James Dongc9dedc42011-05-01 12:36:22 -07001612 abortPrepare(UNKNOWN_ERROR);
1613 return;
1614 }
1615
1616 if (mUri.size() > 0) {
1617 status_t err = finishSetDataSource_l();
1618
1619 if (err != OK) {
1620 abortPrepare(err);
1621 return;
1622 }
1623 }
1624
1625 if (mVideoTrack != NULL && mVideoSource == NULL) {
1626 status_t err = initVideoDecoder();
1627
1628 if (err != OK) {
1629 abortPrepare(err);
1630 return;
1631 }
1632 }
1633
1634 if (mAudioTrack != NULL && mAudioSource == NULL) {
1635 status_t err = initAudioDecoder();
1636
1637 if (err != OK) {
1638 abortPrepare(err);
1639 return;
1640 }
1641 }
1642
1643 mFlags |= PREPARING_CONNECTED;
1644
Andreas Huber4a4a8f02011-10-12 15:08:42 -07001645 if (mCachedSource != NULL) {
James Dongc9dedc42011-05-01 12:36:22 -07001646 postBufferingEvent_l();
1647 } else {
1648 finishAsyncPrepare_l();
1649 }
1650}
1651
1652void PreviewPlayerBase::finishAsyncPrepare_l() {
1653 if (mIsAsyncPrepare) {
1654 if (mVideoSource == NULL) {
1655 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1656 } else {
1657 notifyVideoSize_l();
1658 }
1659
1660 notifyListener_l(MEDIA_PREPARED);
1661 }
1662
1663 mPrepareResult = OK;
1664 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1665 mFlags |= PREPARED;
1666 mAsyncPrepareEvent = NULL;
1667 mPreparedCondition.broadcast();
1668}
1669
1670uint32_t PreviewPlayerBase::flags() const {
1671 return mExtractorFlags;
1672}
1673
1674void PreviewPlayerBase::postAudioEOS(int64_t delayUs) {
1675 Mutex::Autolock autoLock(mLock);
1676 postCheckAudioStatusEvent_l(delayUs);
1677}
1678
1679void PreviewPlayerBase::postAudioSeekComplete() {
1680 Mutex::Autolock autoLock(mLock);
1681 postCheckAudioStatusEvent_l(0 /* delayUs */);
1682}
1683
1684status_t PreviewPlayerBase::setParameter(int key, const Parcel &request) {
1685 return OK;
1686}
1687
1688status_t PreviewPlayerBase::getParameter(int key, Parcel *reply) {
1689 return OK;
1690}
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +08001691
James Dongc9dedc42011-05-01 12:36:22 -07001692} // namespace android