blob: 2a59095134935b82468fe95e8e9ea1925b844346 [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"
James Dongc9dedc42011-05-01 12:36:22 -070026
27#include <binder/IPCThreadState.h>
28#include <binder/IServiceManager.h>
29#include <media/IMediaPlayerService.h>
30#include <media/stagefright/foundation/hexdump.h>
31#include <media/stagefright/foundation/ADebug.h>
32#include <media/stagefright/DataSource.h>
James Dongc9dedc42011-05-01 12:36:22 -070033#include <media/stagefright/MediaBuffer.h>
34#include <media/stagefright/MediaDefs.h>
35#include <media/stagefright/MediaExtractor.h>
36#include <media/stagefright/MediaSource.h>
37#include <media/stagefright/MetaData.h>
38#include <media/stagefright/OMXCodec.h>
39
40#include <surfaceflinger/Surface.h>
41#include <gui/ISurfaceTexture.h>
42#include <gui/SurfaceTextureClient.h>
43#include <surfaceflinger/ISurfaceComposer.h>
44
James Dongc9dedc42011-05-01 12:36:22 -070045#include <cutils/properties.h>
46
47#define USE_SURFACE_ALLOC 1
48
49namespace android {
50
James Dongc9dedc42011-05-01 12:36:22 -070051struct AwesomeEvent : public TimedEventQueue::Event {
52 AwesomeEvent(
53 PreviewPlayerBase *player,
54 void (PreviewPlayerBase::*method)())
55 : mPlayer(player),
56 mMethod(method) {
57 }
58
59protected:
60 virtual ~AwesomeEvent() {}
61
62 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
63 (mPlayer->*mMethod)();
64 }
65
66private:
67 PreviewPlayerBase *mPlayer;
68 void (PreviewPlayerBase::*mMethod)();
69
70 AwesomeEvent(const AwesomeEvent &);
71 AwesomeEvent &operator=(const AwesomeEvent &);
72};
73
74struct AwesomeLocalRenderer : public AwesomeRenderer {
75 AwesomeLocalRenderer(
76 const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
77 : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
78 }
79
80 virtual void render(MediaBuffer *buffer) {
81 render((const uint8_t *)buffer->data() + buffer->range_offset(),
82 buffer->range_length());
83 }
84
85 void render(const void *data, size_t size) {
86 mTarget->render(data, size, NULL);
87 }
88
89protected:
90 virtual ~AwesomeLocalRenderer() {
91 delete mTarget;
92 mTarget = NULL;
93 }
94
95private:
96 SoftwareRenderer *mTarget;
97
98 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
99 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
100};
101
102struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
103 AwesomeNativeWindowRenderer(
104 const sp<ANativeWindow> &nativeWindow,
105 int32_t rotationDegrees)
106 : mNativeWindow(nativeWindow) {
107 applyRotation(rotationDegrees);
108 }
109
110 virtual void render(MediaBuffer *buffer) {
111 status_t err = mNativeWindow->queueBuffer(
112 mNativeWindow.get(), buffer->graphicBuffer().get());
113 if (err != 0) {
Steve Blockf8bd29c2012-01-08 10:14:44 +0000114 ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
James Dongc9dedc42011-05-01 12:36:22 -0700115 -err);
116 return;
117 }
118
119 sp<MetaData> metaData = buffer->meta_data();
120 metaData->setInt32(kKeyRendered, 1);
121 }
122
123protected:
124 virtual ~AwesomeNativeWindowRenderer() {}
125
126private:
127 sp<ANativeWindow> mNativeWindow;
128
129 void applyRotation(int32_t rotationDegrees) {
130 uint32_t transform;
131 switch (rotationDegrees) {
132 case 0: transform = 0; break;
133 case 90: transform = HAL_TRANSFORM_ROT_90; break;
134 case 180: transform = HAL_TRANSFORM_ROT_180; break;
135 case 270: transform = HAL_TRANSFORM_ROT_270; break;
136 default: transform = 0; break;
137 }
138
139 if (transform) {
140 CHECK_EQ(0, native_window_set_buffers_transform(
141 mNativeWindow.get(), transform));
142 }
143 }
144
145 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
146 AwesomeNativeWindowRenderer &operator=(
147 const AwesomeNativeWindowRenderer &);
148};
149
150// To collect the decoder usage
151void addBatteryData(uint32_t params) {
152 sp<IBinder> binder =
153 defaultServiceManager()->getService(String16("media.player"));
154 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
155 CHECK(service.get() != NULL);
156
157 service->addBatteryData(params);
158}
159
160////////////////////////////////////////////////////////////////////////////////
161PreviewPlayerBase::PreviewPlayerBase()
162 : mQueueStarted(false),
163 mTimeSource(NULL),
164 mVideoRendererIsPreview(false),
165 mAudioPlayer(NULL),
166 mDisplayWidth(0),
167 mDisplayHeight(0),
168 mFlags(0),
169 mExtractorFlags(0),
170 mVideoBuffer(NULL),
James Dongc9dedc42011-05-01 12:36:22 -0700171 mLastVideoTimeUs(-1) {
172 CHECK_EQ(mClient.connect(), (status_t)OK);
173
174 DataSource::RegisterDefaultSniffers();
175
176 mVideoEvent = new AwesomeEvent(this, &PreviewPlayerBase::onVideoEvent);
177 mVideoEventPending = false;
178 mStreamDoneEvent = new AwesomeEvent(this, &PreviewPlayerBase::onStreamDone);
179 mStreamDoneEventPending = false;
James Dongc9dedc42011-05-01 12:36:22 -0700180 mVideoLagEvent = new AwesomeEvent(this, &PreviewPlayerBase::onVideoLagUpdate);
181 mVideoEventPending = false;
182
183 mCheckAudioStatusEvent = new AwesomeEvent(
184 this, &PreviewPlayerBase::onCheckAudioStatus);
185
186 mAudioStatusEventPending = false;
187
188 reset();
189}
190
191PreviewPlayerBase::~PreviewPlayerBase() {
192 if (mQueueStarted) {
193 mQueue.stop();
194 }
195
196 reset();
197
198 mClient.disconnect();
199}
200
James Dongdaeb5b32012-01-12 12:12:40 -0800201void PreviewPlayerBase::cancelPlayerEvents() {
James Dongc9dedc42011-05-01 12:36:22 -0700202 mQueue.cancelEvent(mVideoEvent->eventID());
203 mVideoEventPending = false;
204 mQueue.cancelEvent(mStreamDoneEvent->eventID());
205 mStreamDoneEventPending = false;
206 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
207 mAudioStatusEventPending = false;
208 mQueue.cancelEvent(mVideoLagEvent->eventID());
209 mVideoLagEventPending = false;
James Dongc9dedc42011-05-01 12:36:22 -0700210}
211
212void PreviewPlayerBase::setListener(const wp<MediaPlayerBase> &listener) {
213 Mutex::Autolock autoLock(mLock);
214 mListener = listener;
215}
216
James Dongdaeb5b32012-01-12 12:12:40 -0800217status_t PreviewPlayerBase::setDataSource(const char *path) {
James Dongc9dedc42011-05-01 12:36:22 -0700218 Mutex::Autolock autoLock(mLock);
James Dongdaeb5b32012-01-12 12:12:40 -0800219 return setDataSource_l(path);
James Dongc9dedc42011-05-01 12:36:22 -0700220}
221
James Dongdaeb5b32012-01-12 12:12:40 -0800222status_t PreviewPlayerBase::setDataSource_l(const char *path) {
James Dongc9dedc42011-05-01 12:36:22 -0700223 reset_l();
224
James Dongdaeb5b32012-01-12 12:12:40 -0800225 mUri = path;
James Dongc9dedc42011-05-01 12:36:22 -0700226
227 if (!(mFlags & INCOGNITO)) {
Steve Blockec9e6632012-01-04 20:06:05 +0000228 ALOGI("setDataSource_l('%s')", mUri.string());
James Dongc9dedc42011-05-01 12:36:22 -0700229 } else {
Steve Blockec9e6632012-01-04 20:06:05 +0000230 ALOGI("setDataSource_l(URL suppressed)");
James Dongc9dedc42011-05-01 12:36:22 -0700231 }
232
233 // The actual work will be done during preparation in the call to
234 // ::finishSetDataSource_l to avoid blocking the calling thread in
235 // setDataSource for any significant time.
236
237 return OK;
238}
239
James Dongc9dedc42011-05-01 12:36:22 -0700240status_t PreviewPlayerBase::setDataSource(const sp<IStreamSource> &source) {
241 return INVALID_OPERATION;
242}
243
James Dongc9dedc42011-05-01 12:36:22 -0700244status_t PreviewPlayerBase::setDataSource_l(const sp<MediaExtractor> &extractor) {
James Dongc0f8fbe2012-01-11 19:11:31 -0800245 if (extractor == NULL) {
246 return UNKNOWN_ERROR;
247 }
248
249 if (extractor->getDrmFlag()) {
250 ALOGE("Data source is drm protected");
251 return INVALID_OPERATION;
252 }
253
James Dongc9dedc42011-05-01 12:36:22 -0700254 // Attempt to approximate overall stream bitrate by summing all
255 // tracks' individual bitrates, if not all of them advertise bitrate,
256 // we have to fail.
257
258 int64_t totalBitRate = 0;
259
260 for (size_t i = 0; i < extractor->countTracks(); ++i) {
261 sp<MetaData> meta = extractor->getTrackMetaData(i);
262
263 int32_t bitrate;
264 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
265 totalBitRate = -1;
266 break;
267 }
268
269 totalBitRate += bitrate;
270 }
271
272 mBitrate = totalBitRate;
273
Steve Block2703f232011-10-20 11:56:09 +0100274 ALOGV("mBitrate = %lld bits/sec", mBitrate);
James Dongc9dedc42011-05-01 12:36:22 -0700275
276 bool haveAudio = false;
277 bool haveVideo = false;
278 for (size_t i = 0; i < extractor->countTracks(); ++i) {
279 sp<MetaData> meta = extractor->getTrackMetaData(i);
280
281 const char *mime;
282 CHECK(meta->findCString(kKeyMIMEType, &mime));
283
284 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
285 setVideoSource(extractor->getTrack(i));
286 haveVideo = true;
287
288 // Set the presentation/display size
289 int32_t displayWidth, displayHeight;
290 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth);
291 if (success) {
292 success = meta->findInt32(kKeyDisplayHeight, &displayHeight);
293 }
294 if (success) {
295 mDisplayWidth = displayWidth;
296 mDisplayHeight = displayHeight;
297 }
298
299 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
300 setAudioSource(extractor->getTrack(i));
301 haveAudio = true;
302
303 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
304 // Only do this for vorbis audio, none of the other audio
305 // formats even support this ringtone specific hack and
306 // retrieving the metadata on some extractors may turn out
307 // to be very expensive.
308 sp<MetaData> fileMeta = extractor->getMetaData();
309 int32_t loop;
310 if (fileMeta != NULL
311 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
312 mFlags |= AUTO_LOOPING;
313 }
314 }
315 }
316
317 if (haveAudio && haveVideo) {
318 break;
319 }
320 }
321
322 if (!haveAudio && !haveVideo) {
323 return UNKNOWN_ERROR;
324 }
325
326 mExtractorFlags = extractor->flags();
327
328 return OK;
329}
330
331void PreviewPlayerBase::reset() {
332 Mutex::Autolock autoLock(mLock);
333 reset_l();
334}
335
336void PreviewPlayerBase::reset_l() {
337 mDisplayWidth = 0;
338 mDisplayHeight = 0;
339
James Dongc9dedc42011-05-01 12:36:22 -0700340 if (mFlags & PLAYING) {
341 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
342 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
343 params |= IMediaPlayerService::kBatteryDataTrackAudio;
344 }
345 if (mVideoSource != NULL) {
346 params |= IMediaPlayerService::kBatteryDataTrackVideo;
347 }
348 addBatteryData(params);
349 }
350
351 if (mFlags & PREPARING) {
352 mFlags |= PREPARE_CANCELLED;
James Dongc9dedc42011-05-01 12:36:22 -0700353
354 if (mFlags & PREPARING_CONNECTED) {
355 // We are basically done preparing, we're just buffering
356 // enough data to start playback, we can safely interrupt that.
357 finishAsyncPrepare_l();
358 }
359 }
360
361 while (mFlags & PREPARING) {
362 mPreparedCondition.wait(mLock);
363 }
364
365 cancelPlayerEvents();
366
James Dongc9dedc42011-05-01 12:36:22 -0700367 mAudioTrack.clear();
368 mVideoTrack.clear();
369
370 // Shutdown audio first, so that the respone to the reset request
371 // appears to happen instantaneously as far as the user is concerned
372 // If we did this later, audio would continue playing while we
373 // shutdown the video-related resources and the player appear to
374 // not be as responsive to a reset request.
375 if (mAudioPlayer == NULL && mAudioSource != NULL) {
376 // If we had an audio player, it would have effectively
377 // taken possession of the audio source and stopped it when
378 // _it_ is stopped. Otherwise this is still our responsibility.
379 mAudioSource->stop();
380 }
381 mAudioSource.clear();
382
383 mTimeSource = NULL;
384
385 delete mAudioPlayer;
386 mAudioPlayer = NULL;
387
388 mVideoRenderer.clear();
389
James Dongc9dedc42011-05-01 12:36:22 -0700390 if (mVideoSource != NULL) {
391 shutdownVideoDecoder_l();
392 }
393
394 mDurationUs = -1;
395 mFlags = 0;
396 mExtractorFlags = 0;
397 mTimeSourceDeltaUs = 0;
398 mVideoTimeUs = 0;
399
400 mSeeking = NO_SEEK;
401 mSeekNotificationSent = false;
402 mSeekTimeUs = 0;
403
404 mUri.setTo("");
James Dongc9dedc42011-05-01 12:36:22 -0700405
406 mBitrate = -1;
407 mLastVideoTimeUs = -1;
408}
409
410void PreviewPlayerBase::notifyListener_l(int msg, int ext1, int ext2) {
411 if (mListener != NULL) {
412 sp<MediaPlayerBase> listener = mListener.promote();
413
414 if (listener != NULL) {
415 listener->sendEvent(msg, ext1, ext2);
416 }
417 }
418}
419
James Dongc9dedc42011-05-01 12:36:22 -0700420void PreviewPlayerBase::onVideoLagUpdate() {
421 Mutex::Autolock autoLock(mLock);
422 if (!mVideoLagEventPending) {
423 return;
424 }
425 mVideoLagEventPending = false;
426
427 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs();
428 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs;
429
430 if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) {
Steve Block2703f232011-10-20 11:56:09 +0100431 ALOGV("video late by %lld ms.", videoLateByUs / 1000ll);
James Dongc9dedc42011-05-01 12:36:22 -0700432
433 notifyListener_l(
434 MEDIA_INFO,
435 MEDIA_INFO_VIDEO_TRACK_LAGGING,
436 videoLateByUs / 1000ll);
437 }
438
439 postVideoLagEvent_l();
440}
441
James Dongc9dedc42011-05-01 12:36:22 -0700442void PreviewPlayerBase::onStreamDone() {
443 // Posted whenever any stream finishes playing.
444
445 Mutex::Autolock autoLock(mLock);
446 if (!mStreamDoneEventPending) {
447 return;
448 }
449 mStreamDoneEventPending = false;
450
451 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Steve Block2703f232011-10-20 11:56:09 +0100452 ALOGV("MEDIA_ERROR %d", mStreamDoneStatus);
James Dongc9dedc42011-05-01 12:36:22 -0700453
454 notifyListener_l(
455 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
456
457 pause_l(true /* at eos */);
458
459 mFlags |= AT_EOS;
460 return;
461 }
462
463 const bool allDone =
464 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
465 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
466
467 if (!allDone) {
468 return;
469 }
470
471 if (mFlags & (LOOPING | AUTO_LOOPING)) {
472 seekTo_l(0);
473
474 if (mVideoSource != NULL) {
475 postVideoEvent_l();
476 }
477 } else {
Steve Block2703f232011-10-20 11:56:09 +0100478 ALOGV("MEDIA_PLAYBACK_COMPLETE");
James Dongc9dedc42011-05-01 12:36:22 -0700479 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
480
481 pause_l(true /* at eos */);
482
483 mFlags |= AT_EOS;
484 }
485}
486
487status_t PreviewPlayerBase::play() {
488 Mutex::Autolock autoLock(mLock);
489
490 mFlags &= ~CACHE_UNDERRUN;
491
492 return play_l();
493}
494
495status_t PreviewPlayerBase::play_l() {
496 mFlags &= ~SEEK_PREVIEW;
497
498 if (mFlags & PLAYING) {
499 return OK;
500 }
501
502 if (!(mFlags & PREPARED)) {
503 status_t err = prepare_l();
504
505 if (err != OK) {
506 return err;
507 }
508 }
509
510 mFlags |= PLAYING;
511 mFlags |= FIRST_FRAME;
512
James Dongc9dedc42011-05-01 12:36:22 -0700513 if (mAudioSource != NULL) {
514 if (mAudioPlayer == NULL) {
515 if (mAudioSink != NULL) {
516 mAudioPlayer = new AudioPlayerBase(mAudioSink, this);
517 mAudioPlayer->setSource(mAudioSource);
518
519 mTimeSource = mAudioPlayer;
520
521 // If there was a seek request before we ever started,
522 // honor the request now.
523 // Make sure to do this before starting the audio player
524 // to avoid a race condition.
525 seekAudioIfNecessary_l();
526 }
527 }
528
529 CHECK(!(mFlags & AUDIO_RUNNING));
530
531 if (mVideoSource == NULL) {
532 status_t err = startAudioPlayer_l();
533
534 if (err != OK) {
535 delete mAudioPlayer;
536 mAudioPlayer = NULL;
537
538 mFlags &= ~(PLAYING | FIRST_FRAME);
539
James Dongc9dedc42011-05-01 12:36:22 -0700540 return err;
541 }
542 }
543 }
544
545 if (mTimeSource == NULL && mAudioPlayer == NULL) {
546 mTimeSource = &mSystemTimeSource;
547 }
548
549 if (mVideoSource != NULL) {
550 // Kick off video playback
551 postVideoEvent_l();
552
553 if (mAudioSource != NULL && mVideoSource != NULL) {
554 postVideoLagEvent_l();
555 }
556 }
557
558 if (mFlags & AT_EOS) {
559 // Legacy behaviour, if a stream finishes playing and then
560 // is started again, we play from the start...
561 seekTo_l(0);
562 }
563
564 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted
565 | IMediaPlayerService::kBatteryDataTrackDecoder;
566 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
567 params |= IMediaPlayerService::kBatteryDataTrackAudio;
568 }
569 if (mVideoSource != NULL) {
570 params |= IMediaPlayerService::kBatteryDataTrackVideo;
571 }
572 addBatteryData(params);
573
574 return OK;
575}
576
577status_t PreviewPlayerBase::startAudioPlayer_l() {
578 CHECK(!(mFlags & AUDIO_RUNNING));
579
580 if (mAudioSource == NULL || mAudioPlayer == NULL) {
581 return OK;
582 }
583
584 if (!(mFlags & AUDIOPLAYER_STARTED)) {
585 mFlags |= AUDIOPLAYER_STARTED;
586
587 // We've already started the MediaSource in order to enable
588 // the prefetcher to read its data.
589 status_t err = mAudioPlayer->start(
590 true /* sourceAlreadyStarted */);
591
592 if (err != OK) {
593 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
594 return err;
595 }
596 } else {
597 mAudioPlayer->resume();
598 }
599
600 mFlags |= AUDIO_RUNNING;
601
602 mWatchForAudioEOS = true;
603
604 return OK;
605}
606
607void PreviewPlayerBase::notifyVideoSize_l() {
608 sp<MetaData> meta = mVideoSource->getFormat();
609
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800610 int32_t vWidth, vHeight;
James Dongc9dedc42011-05-01 12:36:22 -0700611 int32_t cropLeft, cropTop, cropRight, cropBottom;
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800612
613 CHECK(meta->findInt32(kKeyWidth, &vWidth));
614 CHECK(meta->findInt32(kKeyHeight, &vHeight));
615
616 mGivenWidth = vWidth;
617 mGivenHeight = vHeight;
618
James Dongc9dedc42011-05-01 12:36:22 -0700619 if (!meta->findRect(
620 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
James Dongc9dedc42011-05-01 12:36:22 -0700621
622 cropLeft = cropTop = 0;
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800623 cropRight = vWidth - 1;
624 cropBottom = vHeight - 1;
James Dongc9dedc42011-05-01 12:36:22 -0700625
Steve Block4ca06b02011-12-20 16:24:14 +0000626 ALOGD("got dimensions only %d x %d", vWidth, vHeight);
James Dongc9dedc42011-05-01 12:36:22 -0700627 } else {
Steve Block4ca06b02011-12-20 16:24:14 +0000628 ALOGD("got crop rect %d, %d, %d, %d",
James Dongc9dedc42011-05-01 12:36:22 -0700629 cropLeft, cropTop, cropRight, cropBottom);
630 }
631
Chih-Chung Chang7efb8ef2011-07-22 09:01:36 +0800632 mCropRect.left = cropLeft;
633 mCropRect.right = cropRight;
634 mCropRect.top = cropTop;
635 mCropRect.bottom = cropBottom;
636
James Dongc9dedc42011-05-01 12:36:22 -0700637 int32_t displayWidth;
638 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
Steve Block2703f232011-10-20 11:56:09 +0100639 ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
James Dongc9dedc42011-05-01 12:36:22 -0700640 mDisplayWidth = displayWidth;
641 }
642 int32_t displayHeight;
643 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
Steve Block2703f232011-10-20 11:56:09 +0100644 ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight);
James Dongc9dedc42011-05-01 12:36:22 -0700645 mDisplayHeight = displayHeight;
646 }
647
648 int32_t usableWidth = cropRight - cropLeft + 1;
649 int32_t usableHeight = cropBottom - cropTop + 1;
650 if (mDisplayWidth != 0) {
651 usableWidth = mDisplayWidth;
652 }
653 if (mDisplayHeight != 0) {
654 usableHeight = mDisplayHeight;
655 }
656
657 int32_t rotationDegrees;
658 if (!mVideoTrack->getFormat()->findInt32(
659 kKeyRotation, &rotationDegrees)) {
660 rotationDegrees = 0;
661 }
662
663 if (rotationDegrees == 90 || rotationDegrees == 270) {
664 notifyListener_l(
665 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
666 } else {
667 notifyListener_l(
668 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
669 }
670}
671
672void PreviewPlayerBase::initRenderer_l() {
673 if (mNativeWindow == NULL) {
674 return;
675 }
676
677 sp<MetaData> meta = mVideoSource->getFormat();
678
679 int32_t format;
680 const char *component;
James Dongc9dedc42011-05-01 12:36:22 -0700681 CHECK(meta->findInt32(kKeyColorFormat, &format));
682 CHECK(meta->findCString(kKeyDecoderComponent, &component));
James Dongc9dedc42011-05-01 12:36:22 -0700683
684 int32_t rotationDegrees;
685 if (!mVideoTrack->getFormat()->findInt32(
686 kKeyRotation, &rotationDegrees)) {
687 rotationDegrees = 0;
688 }
689
690 mVideoRenderer.clear();
691
692 // Must ensure that mVideoRenderer's destructor is actually executed
693 // before creating a new one.
694 IPCThreadState::self()->flushCommands();
695
696 if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
697 // Hardware decoders avoid the CPU color conversion by decoding
698 // directly to ANativeBuffers, so we must use a renderer that
699 // just pushes those buffers to the ANativeWindow.
700 mVideoRenderer =
701 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);
702 } else {
703 // Other decoders are instantiated locally and as a consequence
704 // allocate their buffers in local address space. This renderer
705 // then performs a color conversion and copy to get the data
706 // into the ANativeBuffer.
707 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
708 }
709}
710
711status_t PreviewPlayerBase::pause() {
712 Mutex::Autolock autoLock(mLock);
713
714 mFlags &= ~CACHE_UNDERRUN;
715
716 return pause_l();
717}
718
719status_t PreviewPlayerBase::pause_l(bool at_eos) {
720 if (!(mFlags & PLAYING)) {
721 return OK;
722 }
723
James Dongdaeb5b32012-01-12 12:12:40 -0800724 cancelPlayerEvents();
James Dongc9dedc42011-05-01 12:36:22 -0700725
726 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
727 if (at_eos) {
728 // If we played the audio stream to completion we
729 // want to make sure that all samples remaining in the audio
730 // track's queue are played out.
731 mAudioPlayer->pause(true /* playPendingSamples */);
732 } else {
733 mAudioPlayer->pause();
734 }
735
736 mFlags &= ~AUDIO_RUNNING;
737 }
738
739 mFlags &= ~PLAYING;
740
James Dongc9dedc42011-05-01 12:36:22 -0700741 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
742 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
743 params |= IMediaPlayerService::kBatteryDataTrackAudio;
744 }
745 if (mVideoSource != NULL) {
746 params |= IMediaPlayerService::kBatteryDataTrackVideo;
747 }
748
749 addBatteryData(params);
750
751 return OK;
752}
753
754bool PreviewPlayerBase::isPlaying() const {
755 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
756}
757
758void PreviewPlayerBase::setSurface(const sp<Surface> &surface) {
759 Mutex::Autolock autoLock(mLock);
760
761 mSurface = surface;
762 setNativeWindow_l(surface);
763}
764
765void PreviewPlayerBase::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
766 Mutex::Autolock autoLock(mLock);
767
768 mSurface.clear();
769 if (surfaceTexture != NULL) {
770 setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
771 }
772}
773
774void PreviewPlayerBase::shutdownVideoDecoder_l() {
775 if (mVideoBuffer) {
776 mVideoBuffer->release();
777 mVideoBuffer = NULL;
778 }
779
780 mVideoSource->stop();
781
782 // The following hack is necessary to ensure that the OMX
783 // component is completely released by the time we may try
784 // to instantiate it again.
785 wp<MediaSource> tmp = mVideoSource;
786 mVideoSource.clear();
787 while (tmp.promote() != NULL) {
788 usleep(1000);
789 }
790 IPCThreadState::self()->flushCommands();
791}
792
793void PreviewPlayerBase::setNativeWindow_l(const sp<ANativeWindow> &native) {
794 mNativeWindow = native;
795
796 if (mVideoSource == NULL) {
797 return;
798 }
799
Steve Blockec9e6632012-01-04 20:06:05 +0000800 ALOGI("attempting to reconfigure to use new surface");
James Dongc9dedc42011-05-01 12:36:22 -0700801
802 bool wasPlaying = (mFlags & PLAYING) != 0;
803
804 pause_l();
805 mVideoRenderer.clear();
806
807 shutdownVideoDecoder_l();
808
809 CHECK_EQ(initVideoDecoder(), (status_t)OK);
810
811 if (mLastVideoTimeUs >= 0) {
812 mSeeking = SEEK;
813 mSeekNotificationSent = true;
814 mSeekTimeUs = mLastVideoTimeUs;
815 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
816 }
817
818 if (wasPlaying) {
819 play_l();
820 }
821}
822
823void PreviewPlayerBase::setAudioSink(
824 const sp<MediaPlayerBase::AudioSink> &audioSink) {
825 Mutex::Autolock autoLock(mLock);
826
827 mAudioSink = audioSink;
828}
829
830status_t PreviewPlayerBase::setLooping(bool shouldLoop) {
831 Mutex::Autolock autoLock(mLock);
832
833 mFlags = mFlags & ~LOOPING;
834
835 if (shouldLoop) {
836 mFlags |= LOOPING;
837 }
838
839 return OK;
840}
841
842status_t PreviewPlayerBase::getDuration(int64_t *durationUs) {
843 Mutex::Autolock autoLock(mMiscStateLock);
844
845 if (mDurationUs < 0) {
846 return UNKNOWN_ERROR;
847 }
848
849 *durationUs = mDurationUs;
850
851 return OK;
852}
853
854status_t PreviewPlayerBase::getPosition(int64_t *positionUs) {
Andreas Huber4a4a8f02011-10-12 15:08:42 -0700855 if (mSeeking != NO_SEEK) {
James Dongc9dedc42011-05-01 12:36:22 -0700856 *positionUs = mSeekTimeUs;
857 } else if (mVideoSource != NULL
858 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
859 Mutex::Autolock autoLock(mMiscStateLock);
860 *positionUs = mVideoTimeUs;
861 } else if (mAudioPlayer != NULL) {
862 *positionUs = mAudioPlayer->getMediaTimeUs();
863 } else {
864 *positionUs = 0;
865 }
866
867 return OK;
868}
869
870status_t PreviewPlayerBase::seekTo(int64_t timeUs) {
871 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
872 Mutex::Autolock autoLock(mLock);
873 return seekTo_l(timeUs);
874 }
875
876 return OK;
877}
878
James Dongc9dedc42011-05-01 12:36:22 -0700879status_t PreviewPlayerBase::seekTo_l(int64_t timeUs) {
James Dongc9dedc42011-05-01 12:36:22 -0700880 if (mFlags & CACHE_UNDERRUN) {
881 mFlags &= ~CACHE_UNDERRUN;
882 play_l();
883 }
884
885 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) {
886 // Video playback completed before, there's no pending
887 // video event right now. In order for this new seek
888 // to be honored, we need to post one.
889
890 postVideoEvent_l();
891 }
892
893 mSeeking = SEEK;
894 mSeekNotificationSent = false;
895 mSeekTimeUs = timeUs;
896 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
897
898 seekAudioIfNecessary_l();
899
900 if (!(mFlags & PLAYING)) {
Steve Block2703f232011-10-20 11:56:09 +0100901 ALOGV("seeking while paused, sending SEEK_COMPLETE notification"
James Dongc9dedc42011-05-01 12:36:22 -0700902 " immediately.");
903
904 notifyListener_l(MEDIA_SEEK_COMPLETE);
905 mSeekNotificationSent = true;
906
907 if ((mFlags & PREPARED) && mVideoSource != NULL) {
908 mFlags |= SEEK_PREVIEW;
909 postVideoEvent_l();
910 }
911 }
912
913 return OK;
914}
915
916void PreviewPlayerBase::seekAudioIfNecessary_l() {
917 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
918 mAudioPlayer->seekTo(mSeekTimeUs);
919
920 mWatchForAudioSeekComplete = true;
921 mWatchForAudioEOS = true;
James Dongc9dedc42011-05-01 12:36:22 -0700922 }
923}
924
925void PreviewPlayerBase::setAudioSource(sp<MediaSource> source) {
926 CHECK(source != NULL);
927
928 mAudioTrack = source;
929}
930
931status_t PreviewPlayerBase::initAudioDecoder() {
932 sp<MetaData> meta = mAudioTrack->getFormat();
933
934 const char *mime;
935 CHECK(meta->findCString(kKeyMIMEType, &mime));
936
937 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
938 mAudioSource = mAudioTrack;
939 } else {
940 mAudioSource = OMXCodec::Create(
941 mClient.interface(), mAudioTrack->getFormat(),
942 false, // createEncoder
943 mAudioTrack);
944 }
945
946 if (mAudioSource != NULL) {
947 int64_t durationUs;
948 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
949 Mutex::Autolock autoLock(mMiscStateLock);
950 if (mDurationUs < 0 || durationUs > mDurationUs) {
951 mDurationUs = durationUs;
952 }
953 }
954
955 status_t err = mAudioSource->start();
956
957 if (err != OK) {
958 mAudioSource.clear();
959 return err;
960 }
961 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
962 // For legacy reasons we're simply going to ignore the absence
963 // of an audio decoder for QCELP instead of aborting playback
964 // altogether.
965 return OK;
966 }
967
968 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
969}
970
971void PreviewPlayerBase::setVideoSource(sp<MediaSource> source) {
972 CHECK(source != NULL);
973
974 mVideoTrack = source;
975}
976
977status_t PreviewPlayerBase::initVideoDecoder(uint32_t flags) {
Steve Block2703f232011-10-20 11:56:09 +0100978 ALOGV("initVideoDecoder flags=0x%x", flags);
James Dongc9dedc42011-05-01 12:36:22 -0700979 mVideoSource = OMXCodec::Create(
980 mClient.interface(), mVideoTrack->getFormat(),
981 false, // createEncoder
982 mVideoTrack,
983 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
984
985 if (mVideoSource != NULL) {
986 int64_t durationUs;
987 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
988 Mutex::Autolock autoLock(mMiscStateLock);
989 if (mDurationUs < 0 || durationUs > mDurationUs) {
990 mDurationUs = durationUs;
991 }
992 }
993
994 status_t err = mVideoSource->start();
995
996 if (err != OK) {
997 mVideoSource.clear();
998 return err;
999 }
1000 }
1001
1002 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1003}
1004
1005void PreviewPlayerBase::finishSeekIfNecessary(int64_t videoTimeUs) {
1006 if (mSeeking == SEEK_VIDEO_ONLY) {
1007 mSeeking = NO_SEEK;
1008 return;
1009 }
1010
1011 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) {
1012 return;
1013 }
1014
1015 if (mAudioPlayer != NULL) {
Steve Block2703f232011-10-20 11:56:09 +01001016 ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001017
1018 // If we don't have a video time, seek audio to the originally
1019 // requested seek time instead.
1020
1021 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1022 mWatchForAudioSeekComplete = true;
1023 mWatchForAudioEOS = true;
1024 } else if (!mSeekNotificationSent) {
1025 // If we're playing video only, report seek complete now,
1026 // otherwise audio player will notify us later.
1027 notifyListener_l(MEDIA_SEEK_COMPLETE);
1028 mSeekNotificationSent = true;
1029 }
1030
1031 mFlags |= FIRST_FRAME;
1032 mSeeking = NO_SEEK;
James Dongc9dedc42011-05-01 12:36:22 -07001033}
1034
1035void PreviewPlayerBase::onVideoEvent() {
1036 Mutex::Autolock autoLock(mLock);
1037 if (!mVideoEventPending) {
1038 // The event has been cancelled in reset_l() but had already
1039 // been scheduled for execution at that time.
1040 return;
1041 }
1042 mVideoEventPending = false;
1043
1044 if (mSeeking != NO_SEEK) {
1045 if (mVideoBuffer) {
1046 mVideoBuffer->release();
1047 mVideoBuffer = NULL;
1048 }
James Dongc9dedc42011-05-01 12:36:22 -07001049 }
1050
1051 if (!mVideoBuffer) {
1052 MediaSource::ReadOptions options;
1053 if (mSeeking != NO_SEEK) {
Steve Block2703f232011-10-20 11:56:09 +01001054 ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001055
1056 options.setSeekTo(
1057 mSeekTimeUs,
1058 mSeeking == SEEK_VIDEO_ONLY
1059 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
1060 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
1061 }
1062 for (;;) {
Chih-Chung Chang43fcc392011-08-02 16:17:39 +08001063 status_t err = mVideoSource->read(&mVideoBuffer, &options);
James Dongc9dedc42011-05-01 12:36:22 -07001064 options.clearSeekTo();
1065
1066 if (err != OK) {
1067 CHECK(mVideoBuffer == NULL);
1068
1069 if (err == INFO_FORMAT_CHANGED) {
Steve Block2703f232011-10-20 11:56:09 +01001070 ALOGV("VideoSource signalled format change.");
James Dongc9dedc42011-05-01 12:36:22 -07001071
1072 notifyVideoSize_l();
1073
1074 if (mVideoRenderer != NULL) {
1075 mVideoRendererIsPreview = false;
1076 initRenderer_l();
1077 }
1078 continue;
1079 }
1080
1081 // So video playback is complete, but we may still have
1082 // a seek request pending that needs to be applied
1083 // to the audio track.
1084 if (mSeeking != NO_SEEK) {
Steve Block2703f232011-10-20 11:56:09 +01001085 ALOGV("video stream ended while seeking!");
James Dongc9dedc42011-05-01 12:36:22 -07001086 }
1087 finishSeekIfNecessary(-1);
1088
1089 if (mAudioPlayer != NULL
1090 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1091 startAudioPlayer_l();
1092 }
1093
1094 mFlags |= VIDEO_AT_EOS;
1095 postStreamDoneEvent_l(err);
1096 return;
1097 }
1098
1099 if (mVideoBuffer->range_length() == 0) {
1100 // Some decoders, notably the PV AVC software decoder
1101 // return spurious empty buffers that we just want to ignore.
1102
1103 mVideoBuffer->release();
1104 mVideoBuffer = NULL;
1105 continue;
1106 }
1107
1108 break;
1109 }
1110 }
1111
1112 int64_t timeUs;
1113 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1114
1115 mLastVideoTimeUs = timeUs;
1116
1117 if (mSeeking == SEEK_VIDEO_ONLY) {
1118 if (mSeekTimeUs > timeUs) {
Steve Blockec9e6632012-01-04 20:06:05 +00001119 ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
James Dongc9dedc42011-05-01 12:36:22 -07001120 mSeekTimeUs, timeUs);
1121 }
1122 }
1123
1124 {
1125 Mutex::Autolock autoLock(mMiscStateLock);
1126 mVideoTimeUs = timeUs;
1127 }
1128
1129 SeekType wasSeeking = mSeeking;
1130 finishSeekIfNecessary(timeUs);
1131
1132 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
1133 status_t err = startAudioPlayer_l();
1134 if (err != OK) {
Steve Blockf8bd29c2012-01-08 10:14:44 +00001135 ALOGE("Startung the audio player failed w/ err %d", err);
James Dongc9dedc42011-05-01 12:36:22 -07001136 return;
1137 }
1138 }
1139
1140 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1141
1142 if (mFlags & FIRST_FRAME) {
1143 mFlags &= ~FIRST_FRAME;
1144 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
1145 }
1146
1147 int64_t realTimeUs, mediaTimeUs;
1148 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
1149 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1150 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1151 }
1152
1153 if (wasSeeking == SEEK_VIDEO_ONLY) {
1154 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1155
1156 int64_t latenessUs = nowUs - timeUs;
1157
1158 if (latenessUs > 0) {
Steve Blockec9e6632012-01-04 20:06:05 +00001159 ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
James Dongc9dedc42011-05-01 12:36:22 -07001160 }
1161 }
1162
1163 if (wasSeeking == NO_SEEK) {
1164 // Let's display the first frame after seeking right away.
1165
1166 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
1167
1168 int64_t latenessUs = nowUs - timeUs;
1169
1170 if (latenessUs > 500000ll
James Dongc9dedc42011-05-01 12:36:22 -07001171 && mAudioPlayer != NULL
1172 && mAudioPlayer->getMediaTimeMapping(
1173 &realTimeUs, &mediaTimeUs)) {
Steve Blockec9e6632012-01-04 20:06:05 +00001174 ALOGI("we're much too late (%.2f secs), video skipping ahead",
James Dongc9dedc42011-05-01 12:36:22 -07001175 latenessUs / 1E6);
1176
1177 mVideoBuffer->release();
1178 mVideoBuffer = NULL;
1179
1180 mSeeking = SEEK_VIDEO_ONLY;
1181 mSeekTimeUs = mediaTimeUs;
1182
1183 postVideoEvent_l();
1184 return;
1185 }
1186
1187 if (latenessUs > 40000) {
1188 // We're more than 40ms late.
Steve Block2703f232011-10-20 11:56:09 +01001189 ALOGV("we're late by %lld us (%.2f secs), dropping frame",
James Dongc9dedc42011-05-01 12:36:22 -07001190 latenessUs, latenessUs / 1E6);
1191 mVideoBuffer->release();
1192 mVideoBuffer = NULL;
1193
1194 postVideoEvent_l();
1195 return;
1196 }
1197
1198 if (latenessUs < -10000) {
1199 // We're more than 10ms early.
1200
1201 postVideoEvent_l(10000);
1202 return;
1203 }
1204 }
1205
1206 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1207 mVideoRendererIsPreview = false;
1208
1209 initRenderer_l();
1210 }
1211
1212 if (mVideoRenderer != NULL) {
1213 mVideoRenderer->render(mVideoBuffer);
1214 }
1215
1216 mVideoBuffer->release();
1217 mVideoBuffer = NULL;
1218
1219 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) {
1220 mFlags &= ~SEEK_PREVIEW;
1221 return;
1222 }
1223
1224 postVideoEvent_l();
1225}
1226
1227void PreviewPlayerBase::postVideoEvent_l(int64_t delayUs) {
1228 if (mVideoEventPending) {
1229 return;
1230 }
1231
1232 mVideoEventPending = true;
1233 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1234}
1235
1236void PreviewPlayerBase::postStreamDoneEvent_l(status_t status) {
1237 if (mStreamDoneEventPending) {
1238 return;
1239 }
1240 mStreamDoneEventPending = true;
1241
1242 mStreamDoneStatus = status;
1243 mQueue.postEvent(mStreamDoneEvent);
1244}
1245
James Dongc9dedc42011-05-01 12:36:22 -07001246void PreviewPlayerBase::postVideoLagEvent_l() {
1247 if (mVideoLagEventPending) {
1248 return;
1249 }
1250 mVideoLagEventPending = true;
1251 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
1252}
1253
1254void PreviewPlayerBase::postCheckAudioStatusEvent_l(int64_t delayUs) {
1255 if (mAudioStatusEventPending) {
1256 return;
1257 }
1258 mAudioStatusEventPending = true;
1259 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs);
1260}
1261
1262void PreviewPlayerBase::onCheckAudioStatus() {
1263 Mutex::Autolock autoLock(mLock);
1264 if (!mAudioStatusEventPending) {
1265 // Event was dispatched and while we were blocking on the mutex,
1266 // has already been cancelled.
1267 return;
1268 }
1269
1270 mAudioStatusEventPending = false;
1271
1272 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1273 mWatchForAudioSeekComplete = false;
1274
1275 if (!mSeekNotificationSent) {
1276 notifyListener_l(MEDIA_SEEK_COMPLETE);
1277 mSeekNotificationSent = true;
1278 }
1279
1280 mSeeking = NO_SEEK;
1281 }
1282
1283 status_t finalStatus;
1284 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
1285 mWatchForAudioEOS = false;
1286 mFlags |= AUDIO_AT_EOS;
1287 mFlags |= FIRST_FRAME;
1288 postStreamDoneEvent_l(finalStatus);
1289 }
1290}
1291
1292status_t PreviewPlayerBase::prepare() {
1293 Mutex::Autolock autoLock(mLock);
1294 return prepare_l();
1295}
1296
1297status_t PreviewPlayerBase::prepare_l() {
1298 if (mFlags & PREPARED) {
1299 return OK;
1300 }
1301
1302 if (mFlags & PREPARING) {
1303 return UNKNOWN_ERROR;
1304 }
1305
1306 mIsAsyncPrepare = false;
1307 status_t err = prepareAsync_l();
1308
1309 if (err != OK) {
1310 return err;
1311 }
1312
1313 while (mFlags & PREPARING) {
1314 mPreparedCondition.wait(mLock);
1315 }
1316
1317 return mPrepareResult;
1318}
1319
1320status_t PreviewPlayerBase::prepareAsync() {
1321 Mutex::Autolock autoLock(mLock);
1322
1323 if (mFlags & PREPARING) {
1324 return UNKNOWN_ERROR; // async prepare already pending
1325 }
1326
1327 mIsAsyncPrepare = true;
1328 return prepareAsync_l();
1329}
1330
1331status_t PreviewPlayerBase::prepareAsync_l() {
1332 if (mFlags & PREPARING) {
1333 return UNKNOWN_ERROR; // async prepare already pending
1334 }
1335
1336 if (!mQueueStarted) {
1337 mQueue.start();
1338 mQueueStarted = true;
1339 }
1340
1341 mFlags |= PREPARING;
1342 mAsyncPrepareEvent = new AwesomeEvent(
1343 this, &PreviewPlayerBase::onPrepareAsyncEvent);
1344
1345 mQueue.postEvent(mAsyncPrepareEvent);
1346
1347 return OK;
1348}
1349
1350status_t PreviewPlayerBase::finishSetDataSource_l() {
James Dongc0f8fbe2012-01-11 19:11:31 -08001351 sp<DataSource> dataSource =
James Dongdaeb5b32012-01-12 12:12:40 -08001352 DataSource::CreateFromURI(mUri.string(), NULL);
James Dongc9dedc42011-05-01 12:36:22 -07001353
1354 if (dataSource == NULL) {
1355 return UNKNOWN_ERROR;
1356 }
1357
1358 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1359
James Dongc9dedc42011-05-01 12:36:22 -07001360 return setDataSource_l(extractor);
1361}
1362
1363void PreviewPlayerBase::abortPrepare(status_t err) {
1364 CHECK(err != OK);
1365
1366 if (mIsAsyncPrepare) {
1367 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1368 }
1369
1370 mPrepareResult = err;
1371 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1372 mAsyncPrepareEvent = NULL;
1373 mPreparedCondition.broadcast();
1374}
1375
1376// static
1377bool PreviewPlayerBase::ContinuePreparation(void *cookie) {
1378 PreviewPlayerBase *me = static_cast<PreviewPlayerBase *>(cookie);
1379
1380 return (me->mFlags & PREPARE_CANCELLED) == 0;
1381}
1382
1383void PreviewPlayerBase::onPrepareAsyncEvent() {
1384 Mutex::Autolock autoLock(mLock);
1385
1386 if (mFlags & PREPARE_CANCELLED) {
Steve Blockec9e6632012-01-04 20:06:05 +00001387 ALOGI("prepare was cancelled before doing anything");
James Dongc9dedc42011-05-01 12:36:22 -07001388 abortPrepare(UNKNOWN_ERROR);
1389 return;
1390 }
1391
1392 if (mUri.size() > 0) {
1393 status_t err = finishSetDataSource_l();
1394
1395 if (err != OK) {
1396 abortPrepare(err);
1397 return;
1398 }
1399 }
1400
1401 if (mVideoTrack != NULL && mVideoSource == NULL) {
1402 status_t err = initVideoDecoder();
1403
1404 if (err != OK) {
1405 abortPrepare(err);
1406 return;
1407 }
1408 }
1409
1410 if (mAudioTrack != NULL && mAudioSource == NULL) {
1411 status_t err = initAudioDecoder();
1412
1413 if (err != OK) {
1414 abortPrepare(err);
1415 return;
1416 }
1417 }
1418
1419 mFlags |= PREPARING_CONNECTED;
1420
James Dongdaeb5b32012-01-12 12:12:40 -08001421 finishAsyncPrepare_l();
James Dongc9dedc42011-05-01 12:36:22 -07001422}
1423
1424void PreviewPlayerBase::finishAsyncPrepare_l() {
1425 if (mIsAsyncPrepare) {
1426 if (mVideoSource == NULL) {
1427 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1428 } else {
1429 notifyVideoSize_l();
1430 }
1431
1432 notifyListener_l(MEDIA_PREPARED);
1433 }
1434
1435 mPrepareResult = OK;
1436 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
1437 mFlags |= PREPARED;
1438 mAsyncPrepareEvent = NULL;
1439 mPreparedCondition.broadcast();
1440}
1441
1442uint32_t PreviewPlayerBase::flags() const {
1443 return mExtractorFlags;
1444}
1445
1446void PreviewPlayerBase::postAudioEOS(int64_t delayUs) {
1447 Mutex::Autolock autoLock(mLock);
1448 postCheckAudioStatusEvent_l(delayUs);
1449}
1450
1451void PreviewPlayerBase::postAudioSeekComplete() {
1452 Mutex::Autolock autoLock(mLock);
1453 postCheckAudioStatusEvent_l(0 /* delayUs */);
1454}
1455
James Dongc9dedc42011-05-01 12:36:22 -07001456} // namespace android