blob: 41f5f3035b861e50f0b69688a411f073b947d510 [file] [log] [blame]
Andreas Huber27366fc2009-11-20 09:32:46 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "AwesomePlayer"
19#include <utils/Log.h>
20
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080021#include <dlfcn.h>
22
Andreas Huber7a747b82010-06-07 15:19:40 -070023#include "include/ARTSPController.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080024#include "include/AwesomePlayer.h"
Andreas Huber7a747b82010-06-07 15:19:40 -070025#include "include/LiveSource.h"
Andreas Huber1314e732009-12-14 14:18:22 -080026#include "include/SoftwareRenderer.h"
Andreas Huber4d61f602010-06-10 11:17:50 -070027#include "include/NuCachedSource2.h"
28#include "include/ThrottledSource.h"
Andreas Huber54d09722010-10-12 11:34:37 -070029#include "include/MPEG2TSExtractor.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080030
Andreas Huber57648e42010-08-04 10:14:30 -070031#include "ARTPSession.h"
32#include "APacketSource.h"
33#include "ASessionDescription.h"
34#include "UDPPusher.h"
35
Andreas Hubera67d5382009-12-10 15:32:12 -080036#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080037#include <media/stagefright/AudioPlayer.h>
38#include <media/stagefright/DataSource.h>
39#include <media/stagefright/FileSource.h>
40#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080041#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080042#include <media/stagefright/MediaExtractor.h>
43#include <media/stagefright/MediaDebug.h>
44#include <media/stagefright/MediaSource.h>
45#include <media/stagefright/MetaData.h>
46#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080047
Andreas Hubere3c01832010-08-16 08:49:37 -070048#include <surfaceflinger/Surface.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080049
Andreas Huber7a747b82010-06-07 15:19:40 -070050#include <media/stagefright/foundation/ALooper.h>
Andreas Huber202348e2010-06-07 14:35:29 -070051
Andreas Huber6a1f5f92010-11-15 09:03:03 -080052#define USE_SURFACE_ALLOC 1
53
Andreas Huber27366fc2009-11-20 09:32:46 -080054namespace android {
55
Andreas Huber87ab9cd2010-09-03 13:20:33 -070056static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
57static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
58
Andreas Huber27366fc2009-11-20 09:32:46 -080059struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080060 AwesomeEvent(
61 AwesomePlayer *player,
62 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080063 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080064 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080065 }
66
67protected:
68 virtual ~AwesomeEvent() {}
69
70 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080071 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080072 }
73
74private:
75 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080076 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080077
78 AwesomeEvent(const AwesomeEvent &);
79 AwesomeEvent &operator=(const AwesomeEvent &);
80};
81
Andreas Huber1314e732009-12-14 14:18:22 -080082struct AwesomeRemoteRenderer : public AwesomeRenderer {
83 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
84 : mTarget(target) {
85 }
86
87 virtual void render(MediaBuffer *buffer) {
88 void *id;
89 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
90 mTarget->render((IOMX::buffer_id)id);
91 }
92 }
93
94private:
95 sp<IOMXRenderer> mTarget;
96
97 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
98 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
99};
100
101struct AwesomeLocalRenderer : public AwesomeRenderer {
102 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800103 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800104 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -0800105 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700106 const sp<ISurface> &isurface,
107 const sp<Surface> &surface,
Andreas Huber1314e732009-12-14 14:18:22 -0800108 size_t displayWidth, size_t displayHeight,
109 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800110 : mTarget(NULL),
111 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800112 init(previewOnly, componentName,
Andreas Hubere3c01832010-08-16 08:49:37 -0700113 colorFormat, isurface, surface, displayWidth,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800114 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800115 }
116
117 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800118 render((const uint8_t *)buffer->data() + buffer->range_offset(),
119 buffer->range_length());
120 }
121
122 void render(const void *data, size_t size) {
123 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800124 }
125
126protected:
127 virtual ~AwesomeLocalRenderer() {
128 delete mTarget;
129 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800130
131 if (mLibHandle) {
132 dlclose(mLibHandle);
133 mLibHandle = NULL;
134 }
Andreas Huber1314e732009-12-14 14:18:22 -0800135 }
136
137private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800138 VideoRenderer *mTarget;
139 void *mLibHandle;
140
141 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800142 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800143 const char *componentName,
144 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700145 const sp<ISurface> &isurface,
146 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800147 size_t displayWidth, size_t displayHeight,
148 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800149
150 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
151 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
152};
153
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800154void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800155 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800156 const char *componentName,
157 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700158 const sp<ISurface> &isurface,
159 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800160 size_t displayWidth, size_t displayHeight,
161 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800162 if (!previewOnly) {
163 // We will stick to the vanilla software-color-converting renderer
164 // for "previewOnly" mode, to avoid unneccessarily switching overlays
165 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800166
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800167 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800168
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800169 if (mLibHandle) {
170 typedef VideoRenderer *(*CreateRendererFunc)(
171 const sp<ISurface> &surface,
172 const char *componentName,
173 OMX_COLOR_FORMATTYPE colorFormat,
174 size_t displayWidth, size_t displayHeight,
175 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800176
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800177 CreateRendererFunc func =
178 (CreateRendererFunc)dlsym(
179 mLibHandle,
180 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
181 "OMX_COLOR_FORMATTYPEjjjj");
182
183 if (func) {
184 mTarget =
Andreas Hubere3c01832010-08-16 08:49:37 -0700185 (*func)(isurface, componentName, colorFormat,
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800186 displayWidth, displayHeight,
187 decodedWidth, decodedHeight);
188 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800189 }
190 }
191
192 if (mTarget == NULL) {
193 mTarget = new SoftwareRenderer(
194 colorFormat, surface, displayWidth, displayHeight,
195 decodedWidth, decodedHeight);
196 }
197}
198
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700199struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
200 AwesomeNativeWindowRenderer(const sp<ANativeWindow> &nativeWindow)
201 : mNativeWindow(nativeWindow) {
202 }
203
204 virtual void render(MediaBuffer *buffer) {
205 status_t err = mNativeWindow->queueBuffer(
206 mNativeWindow.get(), buffer->graphicBuffer().get());
207 if (err != 0) {
208 LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
209 -err);
210 return;
211 }
212
213 sp<MetaData> metaData = buffer->meta_data();
214 metaData->setInt32(kKeyRendered, 1);
215 }
216
217protected:
218 virtual ~AwesomeNativeWindowRenderer() {}
219
220private:
221 sp<ANativeWindow> mNativeWindow;
222
223 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
224 AwesomeNativeWindowRenderer &operator=(
225 const AwesomeNativeWindowRenderer &);
226};
227
Andreas Huber27366fc2009-11-20 09:32:46 -0800228AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800229 : mQueueStarted(false),
230 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800231 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800232 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800233 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700234 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800235 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800236 mVideoBuffer(NULL),
Gloria Wangd5770912010-06-22 13:55:38 -0700237 mSuspensionState(NULL),
238 mDecryptHandle(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800239 CHECK_EQ(mClient.connect(), OK);
240
241 DataSource::RegisterDefaultSniffers();
242
Andreas Huber6be780e2010-02-08 14:40:30 -0800243 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800244 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800245 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800246 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800247 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800248 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800249
250 mCheckAudioStatusEvent = new AwesomeEvent(
251 this, &AwesomePlayer::onCheckAudioStatus);
252
Andreas Huber70d10c02010-02-03 11:37:29 -0800253 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800254
Andreas Huber27366fc2009-11-20 09:32:46 -0800255 reset();
256}
257
258AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800259 if (mQueueStarted) {
260 mQueue.stop();
261 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800262
263 reset();
264
265 mClient.disconnect();
266}
267
Andreas Huberb9e63832010-01-26 16:20:10 -0800268void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800269 mQueue.cancelEvent(mVideoEvent->eventID());
270 mVideoEventPending = false;
271 mQueue.cancelEvent(mStreamDoneEvent->eventID());
272 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800273 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
274 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800275
276 if (!keepBufferingGoing) {
277 mQueue.cancelEvent(mBufferingEvent->eventID());
278 mBufferingEventPending = false;
279 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800280}
281
Andreas Hubera3f43842010-01-21 10:28:45 -0800282void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800283 Mutex::Autolock autoLock(mLock);
284 mListener = listener;
285}
286
Andreas Huber433c9ac2010-01-27 16:49:05 -0800287status_t AwesomePlayer::setDataSource(
288 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800289 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800290 return setDataSource_l(uri, headers);
291}
Andreas Huber27366fc2009-11-20 09:32:46 -0800292
Andreas Huberba7ec912010-02-12 10:42:02 -0800293status_t AwesomePlayer::setDataSource_l(
294 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800295 reset_l();
296
Andreas Huberffdf4782010-02-09 14:05:43 -0800297 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800298
Andreas Huber6a1f5f92010-11-15 09:03:03 -0800299 if (!strncmp("http://", uri, 7)) {
300 // Hack to support http live.
301
302 size_t len = strlen(uri);
303 if (!strcasecmp(&uri[len - 5], ".m3u8")) {
304 mUri = "httplive://";
305 mUri.append(&uri[7]);
306 }
307 }
308
Andreas Huberffdf4782010-02-09 14:05:43 -0800309 if (headers) {
310 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800311 }
312
Andreas Huberffdf4782010-02-09 14:05:43 -0800313 // The actual work will be done during preparation in the call to
314 // ::finishSetDataSource_l to avoid blocking the calling thread in
315 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800316
Andreas Huberffdf4782010-02-09 14:05:43 -0800317 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800318}
319
320status_t AwesomePlayer::setDataSource(
321 int fd, int64_t offset, int64_t length) {
322 Mutex::Autolock autoLock(mLock);
323
324 reset_l();
325
Andreas Huberba7ec912010-02-12 10:42:02 -0800326 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800327
Andreas Huberba7ec912010-02-12 10:42:02 -0800328 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800329
330 if (err != OK) {
331 return err;
332 }
333
Andreas Huberba7ec912010-02-12 10:42:02 -0800334 mFileSource = dataSource;
335
336 return setDataSource_l(dataSource);
337}
338
339status_t AwesomePlayer::setDataSource_l(
340 const sp<DataSource> &dataSource) {
341 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800342
343 if (extractor == NULL) {
344 return UNKNOWN_ERROR;
345 }
346
Gloria Wangd5770912010-06-22 13:55:38 -0700347 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangeab18ea2010-10-29 10:09:47 -0700348 if (mDecryptHandle != NULL
349 && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
350 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
Gloria Wangd5770912010-06-22 13:55:38 -0700351 }
352
Andreas Huber27366fc2009-11-20 09:32:46 -0800353 return setDataSource_l(extractor);
354}
355
356status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700357 // Attempt to approximate overall stream bitrate by summing all
358 // tracks' individual bitrates, if not all of them advertise bitrate,
359 // we have to fail.
360
361 int64_t totalBitRate = 0;
362
363 for (size_t i = 0; i < extractor->countTracks(); ++i) {
364 sp<MetaData> meta = extractor->getTrackMetaData(i);
365
366 int32_t bitrate;
367 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
368 totalBitRate = -1;
369 break;
370 }
371
372 totalBitRate += bitrate;
373 }
374
375 mBitrate = totalBitRate;
376
377 LOGV("mBitrate = %lld bits/sec", mBitrate);
378
Andreas Huber27366fc2009-11-20 09:32:46 -0800379 bool haveAudio = false;
380 bool haveVideo = false;
381 for (size_t i = 0; i < extractor->countTracks(); ++i) {
382 sp<MetaData> meta = extractor->getTrackMetaData(i);
383
384 const char *mime;
385 CHECK(meta->findCString(kKeyMIMEType, &mime));
386
387 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800388 setVideoSource(extractor->getTrack(i));
389 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800390 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800391 setAudioSource(extractor->getTrack(i));
392 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700393
Andreas Huber1913c1a2010-10-04 11:09:31 -0700394 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
395 // Only do this for vorbis audio, none of the other audio
396 // formats even support this ringtone specific hack and
397 // retrieving the metadata on some extractors may turn out
398 // to be very expensive.
399 sp<MetaData> fileMeta = extractor->getMetaData();
400 int32_t loop;
401 if (fileMeta != NULL
402 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
403 mFlags |= AUTO_LOOPING;
404 }
Andreas Huber9fee0b22010-09-03 14:09:21 -0700405 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800406 }
407
408 if (haveAudio && haveVideo) {
409 break;
410 }
411 }
412
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700413 if (!haveAudio && !haveVideo) {
414 return UNKNOWN_ERROR;
415 }
416
417 mExtractorFlags = extractor->flags();
418
419 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800420}
421
422void AwesomePlayer::reset() {
423 Mutex::Autolock autoLock(mLock);
424 reset_l();
425}
426
427void AwesomePlayer::reset_l() {
Gloria Wangd5770912010-06-22 13:55:38 -0700428 if (mDecryptHandle != NULL) {
429 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
430 Playback::STOP, 0);
Gloria Wangc2c22e72010-11-01 15:53:16 -0700431 mDrmManagerClient->closeDecryptSession(mDecryptHandle);
Gloria Wangd5770912010-06-22 13:55:38 -0700432 mDecryptHandle = NULL;
433 mDrmManagerClient = NULL;
434 }
435
Andreas Huberedbb4d82010-03-12 08:59:22 -0800436 if (mFlags & PREPARING) {
437 mFlags |= PREPARE_CANCELLED;
438 if (mConnectingDataSource != NULL) {
439 LOGI("interrupting the connection process");
440 mConnectingDataSource->disconnect();
441 }
Andreas Hubereaf2c5a2010-10-19 12:18:51 -0700442
443 if (mFlags & PREPARING_CONNECTED) {
444 // We are basically done preparing, we're just buffering
445 // enough data to start playback, we can safely interrupt that.
446 finishAsyncPrepare_l();
447 }
Andreas Huberedbb4d82010-03-12 08:59:22 -0800448 }
449
Andreas Huberffdf4782010-02-09 14:05:43 -0800450 while (mFlags & PREPARING) {
451 mPreparedCondition.wait(mLock);
452 }
453
Andreas Huber27366fc2009-11-20 09:32:46 -0800454 cancelPlayerEvents();
455
Andreas Huber4d61f602010-06-10 11:17:50 -0700456 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800457 mAudioTrack.clear();
458 mVideoTrack.clear();
459
Andreas Huberba7ec912010-02-12 10:42:02 -0800460 // Shutdown audio first, so that the respone to the reset request
461 // appears to happen instantaneously as far as the user is concerned
462 // If we did this later, audio would continue playing while we
463 // shutdown the video-related resources and the player appear to
464 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800465 if (mAudioPlayer == NULL && mAudioSource != NULL) {
466 // If we had an audio player, it would have effectively
467 // taken possession of the audio source and stopped it when
468 // _it_ is stopped. Otherwise this is still our responsibility.
469 mAudioSource->stop();
470 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800471 mAudioSource.clear();
472
Andreas Huberba7ec912010-02-12 10:42:02 -0800473 mTimeSource = NULL;
474
475 delete mAudioPlayer;
476 mAudioPlayer = NULL;
477
Andreas Huber3522b5a52010-01-22 14:36:53 -0800478 mVideoRenderer.clear();
479
Andreas Huber27366fc2009-11-20 09:32:46 -0800480 if (mLastVideoBuffer) {
481 mLastVideoBuffer->release();
482 mLastVideoBuffer = NULL;
483 }
484
485 if (mVideoBuffer) {
486 mVideoBuffer->release();
487 mVideoBuffer = NULL;
488 }
489
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700490 if (mRTSPController != NULL) {
491 mRTSPController->disconnect();
492 mRTSPController.clear();
493 }
494
Andreas Huber57648e42010-08-04 10:14:30 -0700495 mRTPPusher.clear();
496 mRTCPPusher.clear();
497 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700498
Andreas Huber27366fc2009-11-20 09:32:46 -0800499 if (mVideoSource != NULL) {
500 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800501
502 // The following hack is necessary to ensure that the OMX
503 // component is completely released by the time we may try
504 // to instantiate it again.
505 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800506 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800507 while (tmp.promote() != NULL) {
508 usleep(1000);
509 }
510 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800511 }
512
Andreas Huber27366fc2009-11-20 09:32:46 -0800513 mDurationUs = -1;
514 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700515 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800516 mVideoWidth = mVideoHeight = -1;
517 mTimeSourceDeltaUs = 0;
518 mVideoTimeUs = 0;
519
520 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700521 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800522 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800523
Andreas Huberffdf4782010-02-09 14:05:43 -0800524 mUri.setTo("");
525 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800526
527 mFileSource.clear();
528
529 delete mSuspensionState;
530 mSuspensionState = NULL;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700531
532 mBitrate = -1;
Andreas Huber27366fc2009-11-20 09:32:46 -0800533}
534
Andreas Huber6be780e2010-02-08 14:40:30 -0800535void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800536 if (mListener != NULL) {
537 sp<MediaPlayerBase> listener = mListener.promote();
538
539 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800540 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800541 }
542 }
543}
544
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700545bool AwesomePlayer::getBitrate(int64_t *bitrate) {
546 off_t size;
547 if (mDurationUs >= 0 && mCachedSource != NULL
548 && mCachedSource->getSize(&size) == OK) {
549 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
550 return true;
551 }
552
553 if (mBitrate >= 0) {
554 *bitrate = mBitrate;
555 return true;
556 }
557
558 *bitrate = 0;
559
560 return false;
561}
562
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700563// Returns true iff cached duration is available/applicable.
564bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700565 int64_t bitrate;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700566
567 if (mRTSPController != NULL) {
568 *durationUs = mRTSPController->getQueueDurationUs(eos);
569 return true;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700570 } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700571 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
572 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
573 return true;
574 }
575
576 return false;
577}
578
Andreas Huber10b920c2010-11-11 15:37:17 -0800579void AwesomePlayer::ensureCacheIsFetching_l() {
580 if (mCachedSource != NULL) {
581 mCachedSource->resumeFetchingIfNecessary();
582 }
583}
584
Andreas Huberb9e63832010-01-26 16:20:10 -0800585void AwesomePlayer::onBufferingUpdate() {
586 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800587 if (!mBufferingEventPending) {
588 return;
589 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800590 mBufferingEventPending = false;
591
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700592 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700593 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700594 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700595
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700596 if (eos) {
597 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700598 if (mFlags & PREPARING) {
599 LOGV("cache has reached EOS, prepare is done.");
600 finishAsyncPrepare_l();
601 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700602 } else {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700603 int64_t bitrate;
604 if (getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700605 size_t cachedSize = mCachedSource->cachedSize();
606 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
607
608 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
609 if (percentage > 100) {
610 percentage = 100;
611 }
612
613 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
614 } else {
615 // We don't know the bitrate of the stream, use absolute size
616 // limits to maintain the cache.
617
Andreas Huber54d09722010-10-12 11:34:37 -0700618 const size_t kLowWaterMarkBytes = 40000;
619 const size_t kHighWaterMarkBytes = 200000;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700620
621 if ((mFlags & PLAYING) && !eos
622 && (cachedDataRemaining < kLowWaterMarkBytes)) {
623 LOGI("cache is running low (< %d) , pausing.",
624 kLowWaterMarkBytes);
625 mFlags |= CACHE_UNDERRUN;
626 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800627 ensureCacheIsFetching_l();
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700628 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
629 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
630 if (mFlags & CACHE_UNDERRUN) {
631 LOGI("cache has filled up (> %d), resuming.",
632 kHighWaterMarkBytes);
633 mFlags &= ~CACHE_UNDERRUN;
634 play_l();
635 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
636 } else if (mFlags & PREPARING) {
637 LOGV("cache has filled up (> %d), prepare is done",
638 kHighWaterMarkBytes);
639 finishAsyncPrepare_l();
640 }
641 }
642 }
643 }
644 }
645
646 int64_t cachedDurationUs;
647 bool eos;
648 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber10b920c2010-11-11 15:37:17 -0800649 LOGV("cachedDurationUs = %.2f secs, eos=%d",
650 cachedDurationUs / 1E6, eos);
651
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700652 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700653 && (cachedDurationUs < kLowWaterMarkUs)) {
654 LOGI("cache is running low (%.2f secs) , pausing.",
655 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700656 mFlags |= CACHE_UNDERRUN;
657 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800658 ensureCacheIsFetching_l();
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700659 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700660 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
661 if (mFlags & CACHE_UNDERRUN) {
662 LOGI("cache has filled up (%.2f secs), resuming.",
663 cachedDurationUs / 1E6);
664 mFlags &= ~CACHE_UNDERRUN;
665 play_l();
666 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
667 } else if (mFlags & PREPARING) {
668 LOGV("cache has filled up (%.2f secs), prepare is done",
669 cachedDurationUs / 1E6);
670 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700671 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700672 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800673 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700674
Andreas Huber4d61f602010-06-10 11:17:50 -0700675 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800676}
677
Andreas Huber4c19bf92010-09-08 14:32:20 -0700678void AwesomePlayer::partial_reset_l() {
679 // Only reset the video renderer and shut down the video decoder.
680 // Then instantiate a new video decoder and resume video playback.
681
682 mVideoRenderer.clear();
683
684 if (mLastVideoBuffer) {
685 mLastVideoBuffer->release();
686 mLastVideoBuffer = NULL;
687 }
688
689 if (mVideoBuffer) {
690 mVideoBuffer->release();
691 mVideoBuffer = NULL;
692 }
693
694 {
695 mVideoSource->stop();
696
697 // The following hack is necessary to ensure that the OMX
698 // component is completely released by the time we may try
699 // to instantiate it again.
700 wp<MediaSource> tmp = mVideoSource;
701 mVideoSource.clear();
702 while (tmp.promote() != NULL) {
703 usleep(1000);
704 }
705 IPCThreadState::self()->flushCommands();
706 }
707
708 CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
709}
710
Andreas Huber27366fc2009-11-20 09:32:46 -0800711void AwesomePlayer::onStreamDone() {
712 // Posted whenever any stream finishes playing.
713
714 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800715 if (!mStreamDoneEventPending) {
716 return;
717 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800718 mStreamDoneEventPending = false;
719
Andreas Huber4c19bf92010-09-08 14:32:20 -0700720 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
721 // This special status is returned because an http live stream's
722 // video stream switched to a different bandwidth at this point
723 // and future data may have been encoded using different parameters.
724 // This requires us to shutdown the video decoder and reinstantiate
725 // a fresh one.
726
727 LOGV("INFO_DISCONTINUITY");
728
729 CHECK(mVideoSource != NULL);
730
731 partial_reset_l();
732 postVideoEvent_l();
733 return;
734 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700735 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
736
737 notifyListener_l(
738 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
739
Andreas Huberc743f452010-10-05 10:25:34 -0700740 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700741
742 mFlags |= AT_EOS;
743 return;
744 }
745
746 const bool allDone =
747 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
748 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
749
750 if (!allDone) {
751 return;
752 }
753
Andreas Huber9fee0b22010-09-03 14:09:21 -0700754 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800755 seekTo_l(0);
756
Andreas Huber7085b6842010-02-03 16:02:02 -0800757 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800758 postVideoEvent_l();
759 }
760 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700761 LOGV("MEDIA_PLAYBACK_COMPLETE");
762 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800763
Andreas Huberc743f452010-10-05 10:25:34 -0700764 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800765
766 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800767 }
768}
769
770status_t AwesomePlayer::play() {
771 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700772
773 mFlags &= ~CACHE_UNDERRUN;
774
Andreas Huberba7ec912010-02-12 10:42:02 -0800775 return play_l();
776}
Andreas Huber27366fc2009-11-20 09:32:46 -0800777
Andreas Huberba7ec912010-02-12 10:42:02 -0800778status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800779 if (mFlags & PLAYING) {
780 return OK;
781 }
782
Andreas Huberffdf4782010-02-09 14:05:43 -0800783 if (!(mFlags & PREPARED)) {
784 status_t err = prepare_l();
785
786 if (err != OK) {
787 return err;
788 }
789 }
790
Andreas Huber27366fc2009-11-20 09:32:46 -0800791 mFlags |= PLAYING;
792 mFlags |= FIRST_FRAME;
793
Andreas Huberc1d5c922009-12-10 15:49:04 -0800794 bool deferredAudioSeek = false;
795
Andreas Huber27366fc2009-11-20 09:32:46 -0800796 if (mAudioSource != NULL) {
797 if (mAudioPlayer == NULL) {
798 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700799 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800800 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800801
802 // We've already started the MediaSource in order to enable
803 // the prefetcher to read its data.
804 status_t err = mAudioPlayer->start(
805 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800806
807 if (err != OK) {
808 delete mAudioPlayer;
809 mAudioPlayer = NULL;
810
811 mFlags &= ~(PLAYING | FIRST_FRAME);
812
813 return err;
814 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800815
Andreas Huber27366fc2009-11-20 09:32:46 -0800816 mTimeSource = mAudioPlayer;
817
Andreas Huberc1d5c922009-12-10 15:49:04 -0800818 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800819
820 mWatchForAudioSeekComplete = false;
821 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800822 }
823 } else {
824 mAudioPlayer->resume();
825 }
826 }
827
828 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700829 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800830 }
831
832 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800833 // Kick off video playback
834 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800835 }
836
Andreas Huberc1d5c922009-12-10 15:49:04 -0800837 if (deferredAudioSeek) {
838 // If there was a seek request while we were paused
839 // and we're just starting up again, honor the request now.
840 seekAudioIfNecessary_l();
841 }
842
Andreas Huber406a18b2010-02-18 16:45:13 -0800843 if (mFlags & AT_EOS) {
844 // Legacy behaviour, if a stream finishes playing and then
845 // is started again, we play from the start...
846 seekTo_l(0);
847 }
848
Gloria Wangd5770912010-06-22 13:55:38 -0700849 if (mDecryptHandle != NULL) {
850 int64_t position;
851 getPosition(&position);
852 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
853 Playback::START, position / 1000);
854 }
855
Andreas Huber27366fc2009-11-20 09:32:46 -0800856 return OK;
857}
858
Andreas Hubere3c01832010-08-16 08:49:37 -0700859void AwesomePlayer::notifyVideoSize_l() {
860 sp<MetaData> meta = mVideoSource->getFormat();
861
862 int32_t decodedWidth, decodedHeight;
863 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
864 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
865
866 notifyListener_l(MEDIA_SET_VIDEO_SIZE, decodedWidth, decodedHeight);
867}
868
Andreas Huber27366fc2009-11-20 09:32:46 -0800869void AwesomePlayer::initRenderer_l() {
Andreas Hubere3c01832010-08-16 08:49:37 -0700870 if (mSurface != NULL || mISurface != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800871 sp<MetaData> meta = mVideoSource->getFormat();
872
873 int32_t format;
874 const char *component;
875 int32_t decodedWidth, decodedHeight;
876 CHECK(meta->findInt32(kKeyColorFormat, &format));
877 CHECK(meta->findCString(kKeyDecoderComponent, &component));
878 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
879 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
880
Andreas Hubera67d5382009-12-10 15:32:12 -0800881 mVideoRenderer.clear();
882
883 // Must ensure that mVideoRenderer's destructor is actually executed
884 // before creating a new one.
885 IPCThreadState::self()->flushCommands();
886
Andreas Hubere3c01832010-08-16 08:49:37 -0700887 if (mSurface != NULL) {
Andreas Huber6a1f5f92010-11-15 09:03:03 -0800888 if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700889 // Hardware decoders avoid the CPU color conversion by decoding
890 // directly to ANativeBuffers, so we must use a renderer that
891 // just pushes those buffers to the ANativeWindow.
892 mVideoRenderer = new AwesomeNativeWindowRenderer(mSurface);
893 } else {
894 // Other decoders are instantiated locally and as a consequence
895 // allocate their buffers in local address space. This renderer
896 // then performs a color conversion and copy to get the data
897 // into the ANativeBuffer.
898 mVideoRenderer = new AwesomeLocalRenderer(
899 false, // previewOnly
900 component,
901 (OMX_COLOR_FORMATTYPE)format,
902 mISurface,
903 mSurface,
904 mVideoWidth, mVideoHeight,
905 decodedWidth, decodedHeight);
906 }
Andreas Hubere3c01832010-08-16 08:49:37 -0700907 } else {
Andreas Huber1314e732009-12-14 14:18:22 -0800908 // Our OMX codecs allocate buffers on the media_server side
909 // therefore they require a remote IOMXRenderer that knows how
910 // to display them.
911 mVideoRenderer = new AwesomeRemoteRenderer(
912 mClient.interface()->createRenderer(
913 mISurface, component,
914 (OMX_COLOR_FORMATTYPE)format,
915 decodedWidth, decodedHeight,
916 mVideoWidth, mVideoHeight));
Andreas Huber1314e732009-12-14 14:18:22 -0800917 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800918 }
919}
920
921status_t AwesomePlayer::pause() {
922 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700923
924 mFlags &= ~CACHE_UNDERRUN;
925
Andreas Huber27366fc2009-11-20 09:32:46 -0800926 return pause_l();
927}
928
Andreas Huberc743f452010-10-05 10:25:34 -0700929status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800930 if (!(mFlags & PLAYING)) {
931 return OK;
932 }
933
Andreas Huberb9e63832010-01-26 16:20:10 -0800934 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800935
936 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -0700937 if (at_eos) {
938 // If we played the audio stream to completion we
939 // want to make sure that all samples remaining in the audio
940 // track's queue are played out.
941 mAudioPlayer->pause(true /* playPendingSamples */);
942 } else {
943 mAudioPlayer->pause();
944 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800945 }
946
947 mFlags &= ~PLAYING;
948
Gloria Wangd5770912010-06-22 13:55:38 -0700949 if (mDecryptHandle != NULL) {
950 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
951 Playback::PAUSE, 0);
952 }
953
Andreas Huber27366fc2009-11-20 09:32:46 -0800954 return OK;
955}
956
957bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700958 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800959}
960
961void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
962 Mutex::Autolock autoLock(mLock);
963
964 mISurface = isurface;
965}
966
Andreas Hubere3c01832010-08-16 08:49:37 -0700967void AwesomePlayer::setSurface(const sp<Surface> &surface) {
968 Mutex::Autolock autoLock(mLock);
969
970 mSurface = surface;
971}
972
Andreas Huber27366fc2009-11-20 09:32:46 -0800973void AwesomePlayer::setAudioSink(
974 const sp<MediaPlayerBase::AudioSink> &audioSink) {
975 Mutex::Autolock autoLock(mLock);
976
977 mAudioSink = audioSink;
978}
979
980status_t AwesomePlayer::setLooping(bool shouldLoop) {
981 Mutex::Autolock autoLock(mLock);
982
983 mFlags = mFlags & ~LOOPING;
984
985 if (shouldLoop) {
986 mFlags |= LOOPING;
987 }
988
989 return OK;
990}
991
992status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700993 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800994
995 if (mDurationUs < 0) {
996 return UNKNOWN_ERROR;
997 }
998
999 *durationUs = mDurationUs;
1000
1001 return OK;
1002}
1003
1004status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -07001005 if (mRTSPController != NULL) {
1006 *positionUs = mRTSPController->getNormalPlayTimeUs();
1007 }
1008 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -07001009 *positionUs = mSeekTimeUs;
1010 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -07001011 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001012 *positionUs = mVideoTimeUs;
1013 } else if (mAudioPlayer != NULL) {
1014 *positionUs = mAudioPlayer->getMediaTimeUs();
1015 } else {
1016 *positionUs = 0;
1017 }
1018
1019 return OK;
1020}
1021
1022status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -07001023 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001024 Mutex::Autolock autoLock(mLock);
1025 return seekTo_l(timeUs);
1026 }
1027
1028 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -08001029}
1030
Andreas Huber0c46b692010-10-08 15:21:08 -07001031// static
1032void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
1033 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
1034}
1035
1036void AwesomePlayer::onRTSPSeekDone() {
1037 notifyListener_l(MEDIA_SEEK_COMPLETE);
1038 mSeekNotificationSent = true;
1039}
1040
Andreas Huber27366fc2009-11-20 09:32:46 -08001041status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001042 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -07001043 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001044 return OK;
1045 }
1046
Andreas Huber4d61f602010-06-10 11:17:50 -07001047 if (mFlags & CACHE_UNDERRUN) {
1048 mFlags &= ~CACHE_UNDERRUN;
1049 play_l();
1050 }
1051
Andreas Huber27366fc2009-11-20 09:32:46 -08001052 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001053 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001054 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001055 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -08001056
1057 seekAudioIfNecessary_l();
1058
Andreas Huber8e2b9412010-03-31 09:40:15 -07001059 if (!(mFlags & PLAYING)) {
1060 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1061 " immediately.");
1062
1063 notifyListener_l(MEDIA_SEEK_COMPLETE);
1064 mSeekNotificationSent = true;
1065 }
1066
Andreas Huber27366fc2009-11-20 09:32:46 -08001067 return OK;
1068}
1069
1070void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -08001071 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001072 mAudioPlayer->seekTo(mSeekTimeUs);
1073
Andreas Huber70d10c02010-02-03 11:37:29 -08001074 mWatchForAudioSeekComplete = true;
1075 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001076 mSeekNotificationSent = false;
Gloria Wangd5770912010-06-22 13:55:38 -07001077
1078 if (mDecryptHandle != NULL) {
1079 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1080 Playback::PAUSE, 0);
1081 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1082 Playback::START, mSeekTimeUs / 1000);
1083 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001084 }
1085}
1086
1087status_t AwesomePlayer::getVideoDimensions(
1088 int32_t *width, int32_t *height) const {
1089 Mutex::Autolock autoLock(mLock);
1090
1091 if (mVideoWidth < 0 || mVideoHeight < 0) {
1092 return UNKNOWN_ERROR;
1093 }
1094
1095 *width = mVideoWidth;
1096 *height = mVideoHeight;
1097
1098 return OK;
1099}
1100
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001101void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1102 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001103
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001104 mAudioTrack = source;
1105}
1106
1107status_t AwesomePlayer::initAudioDecoder() {
1108 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -08001109
1110 const char *mime;
1111 CHECK(meta->findCString(kKeyMIMEType, &mime));
1112
1113 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001114 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -08001115 } else {
1116 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001117 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -08001118 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001119 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -08001120 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001121
1122 if (mAudioSource != NULL) {
1123 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001124 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001125 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001126 if (mDurationUs < 0 || durationUs > mDurationUs) {
1127 mDurationUs = durationUs;
1128 }
1129 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001130
Andreas Huber3c78a1b2010-05-13 09:15:21 -07001131 status_t err = mAudioSource->start();
1132
1133 if (err != OK) {
1134 mAudioSource.clear();
1135 return err;
1136 }
Andreas Huberd0332ad2010-04-12 16:05:57 -07001137 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1138 // For legacy reasons we're simply going to ignore the absence
1139 // of an audio decoder for QCELP instead of aborting playback
1140 // altogether.
1141 return OK;
1142 }
Andreas Huberdc9927d2010-03-08 15:46:13 -08001143
Andreas Huber27366fc2009-11-20 09:32:46 -08001144 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1145}
1146
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001147void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1148 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001149
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001150 mVideoTrack = source;
1151}
1152
Andreas Huber4c19bf92010-09-08 14:32:20 -07001153status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001154 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001155 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -08001156 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -07001157 mVideoTrack,
Andreas Huber6a1f5f92010-11-15 09:03:03 -08001158 NULL, flags, USE_SURFACE_ALLOC ? mSurface : NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001159
1160 if (mVideoSource != NULL) {
1161 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001162 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001163 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001164 if (mDurationUs < 0 || durationUs > mDurationUs) {
1165 mDurationUs = durationUs;
1166 }
1167 }
1168
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001169 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
1170 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -08001171
Andreas Huber1919e5a2010-05-20 10:37:06 -07001172 status_t err = mVideoSource->start();
1173
1174 if (err != OK) {
1175 mVideoSource.clear();
1176 return err;
1177 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001178 }
1179
1180 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1181}
1182
Andreas Huber4d450a82010-10-19 09:34:44 -07001183void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1184 if (!mSeeking) {
1185 return;
1186 }
1187
1188 if (mAudioPlayer != NULL) {
Jamie Gennis6913c612010-10-20 15:55:43 -07001189 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
Andreas Huber4d450a82010-10-19 09:34:44 -07001190
1191 // If we don't have a video time, seek audio to the originally
1192 // requested seek time instead.
1193
1194 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1195 mAudioPlayer->resume();
1196 mWatchForAudioSeekComplete = true;
1197 mWatchForAudioEOS = true;
1198 } else if (!mSeekNotificationSent) {
1199 // If we're playing video only, report seek complete now,
1200 // otherwise audio player will notify us later.
1201 notifyListener_l(MEDIA_SEEK_COMPLETE);
1202 }
1203
1204 mFlags |= FIRST_FRAME;
1205 mSeeking = false;
1206 mSeekNotificationSent = false;
Gloria Wang3f9a8192010-10-29 14:50:17 -07001207
1208 if (mDecryptHandle != NULL) {
1209 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1210 Playback::PAUSE, 0);
1211 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1212 Playback::START, videoTimeUs / 1000);
1213 }
Andreas Huber4d450a82010-10-19 09:34:44 -07001214}
1215
Andreas Huber6be780e2010-02-08 14:40:30 -08001216void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001217 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001218 if (!mVideoEventPending) {
1219 // The event has been cancelled in reset_l() but had already
1220 // been scheduled for execution at that time.
1221 return;
1222 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001223 mVideoEventPending = false;
1224
1225 if (mSeeking) {
1226 if (mLastVideoBuffer) {
1227 mLastVideoBuffer->release();
1228 mLastVideoBuffer = NULL;
1229 }
1230
1231 if (mVideoBuffer) {
1232 mVideoBuffer->release();
1233 mVideoBuffer = NULL;
1234 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001235
1236 if (mCachedSource != NULL && mAudioSource != NULL) {
1237 // We're going to seek the video source first, followed by
1238 // the audio source.
1239 // In order to avoid jumps in the DataSource offset caused by
1240 // the audio codec prefetching data from the old locations
1241 // while the video codec is already reading data from the new
1242 // locations, we'll "pause" the audio source, causing it to
1243 // stop reading input data until a subsequent seek.
1244
1245 if (mAudioPlayer != NULL) {
1246 mAudioPlayer->pause();
1247 }
1248 mAudioSource->pause();
1249 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001250 }
1251
1252 if (!mVideoBuffer) {
1253 MediaSource::ReadOptions options;
1254 if (mSeeking) {
1255 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1256
Andreas Huber6624c9f2010-07-20 15:04:28 -07001257 options.setSeekTo(
1258 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001259 }
1260 for (;;) {
1261 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001262 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001263
1264 if (err != OK) {
1265 CHECK_EQ(mVideoBuffer, NULL);
1266
1267 if (err == INFO_FORMAT_CHANGED) {
1268 LOGV("VideoSource signalled format change.");
1269
Andreas Hubere3c01832010-08-16 08:49:37 -07001270 notifyVideoSize_l();
1271
Andreas Huber7085b6842010-02-03 16:02:02 -08001272 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001273 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001274 initRenderer_l();
1275 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001276 continue;
1277 }
1278
Andreas Huber4d450a82010-10-19 09:34:44 -07001279 // So video playback is complete, but we may still have
1280 // a seek request pending that needs to be applied
1281 // to the audio track.
1282 if (mSeeking) {
1283 LOGV("video stream ended while seeking!");
1284 }
1285 finishSeekIfNecessary(-1);
1286
Andreas Huber971305d2010-07-07 13:35:27 -07001287 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001288 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001289 return;
1290 }
1291
Andreas Hubera67d5382009-12-10 15:32:12 -08001292 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001293 // Some decoders, notably the PV AVC software decoder
1294 // return spurious empty buffers that we just want to ignore.
1295
Andreas Hubera67d5382009-12-10 15:32:12 -08001296 mVideoBuffer->release();
1297 mVideoBuffer = NULL;
1298 continue;
1299 }
1300
Andreas Huber27366fc2009-11-20 09:32:46 -08001301 break;
1302 }
1303 }
1304
1305 int64_t timeUs;
1306 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1307
Andreas Huber252573c2010-03-26 10:17:17 -07001308 {
1309 Mutex::Autolock autoLock(mMiscStateLock);
1310 mVideoTimeUs = timeUs;
1311 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001312
Andreas Huber614d22c2010-10-29 15:47:52 -07001313 bool wasSeeking = mSeeking;
Andreas Huber4d450a82010-10-19 09:34:44 -07001314 finishSeekIfNecessary(timeUs);
Andreas Huber27366fc2009-11-20 09:32:46 -08001315
Andreas Huber971305d2010-07-07 13:35:27 -07001316 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1317
Andreas Huber27366fc2009-11-20 09:32:46 -08001318 if (mFlags & FIRST_FRAME) {
1319 mFlags &= ~FIRST_FRAME;
1320
Andreas Huber971305d2010-07-07 13:35:27 -07001321 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001322 }
1323
1324 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001325 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001326 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1327 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1328 }
1329
Andreas Huber971305d2010-07-07 13:35:27 -07001330 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001331
1332 int64_t latenessUs = nowUs - timeUs;
1333
Andreas Huber614d22c2010-10-29 15:47:52 -07001334 if (wasSeeking) {
1335 // Let's display the first frame after seeking right away.
1336 latenessUs = 0;
1337 }
1338
Andreas Huberf88f8442010-08-10 11:18:36 -07001339 if (mRTPSession != NULL) {
1340 // We'll completely ignore timestamps for gtalk videochat
1341 // and we'll play incoming video as fast as we get it.
1342 latenessUs = 0;
1343 }
1344
Andreas Huber24b0a952009-11-23 14:02:00 -08001345 if (latenessUs > 40000) {
1346 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001347 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001348
1349 mVideoBuffer->release();
1350 mVideoBuffer = NULL;
1351
1352 postVideoEvent_l();
1353 return;
1354 }
1355
1356 if (latenessUs < -10000) {
1357 // We're more than 10ms early.
1358
1359 postVideoEvent_l(10000);
1360 return;
1361 }
1362
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001363 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1364 mVideoRendererIsPreview = false;
1365
Andreas Huber7085b6842010-02-03 16:02:02 -08001366 initRenderer_l();
1367 }
1368
1369 if (mVideoRenderer != NULL) {
1370 mVideoRenderer->render(mVideoBuffer);
1371 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001372
1373 if (mLastVideoBuffer) {
1374 mLastVideoBuffer->release();
1375 mLastVideoBuffer = NULL;
1376 }
1377 mLastVideoBuffer = mVideoBuffer;
1378 mVideoBuffer = NULL;
1379
1380 postVideoEvent_l();
1381}
1382
1383void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1384 if (mVideoEventPending) {
1385 return;
1386 }
1387
1388 mVideoEventPending = true;
1389 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1390}
1391
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001392void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001393 if (mStreamDoneEventPending) {
1394 return;
1395 }
1396 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001397
1398 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001399 mQueue.postEvent(mStreamDoneEvent);
1400}
1401
Andreas Huberb9e63832010-01-26 16:20:10 -08001402void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001403 if (mBufferingEventPending) {
1404 return;
1405 }
1406 mBufferingEventPending = true;
1407 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1408}
1409
Andreas Huber70d10c02010-02-03 11:37:29 -08001410void AwesomePlayer::postCheckAudioStatusEvent_l() {
1411 if (mAudioStatusEventPending) {
1412 return;
1413 }
1414 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001415 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001416}
1417
1418void AwesomePlayer::onCheckAudioStatus() {
1419 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001420 if (!mAudioStatusEventPending) {
1421 // Event was dispatched and while we were blocking on the mutex,
1422 // has already been cancelled.
1423 return;
1424 }
1425
Andreas Huber70d10c02010-02-03 11:37:29 -08001426 mAudioStatusEventPending = false;
1427
1428 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1429 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001430
1431 if (!mSeekNotificationSent) {
1432 notifyListener_l(MEDIA_SEEK_COMPLETE);
1433 mSeekNotificationSent = true;
1434 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001435
1436 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001437 }
1438
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001439 status_t finalStatus;
1440 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001441 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001442 mFlags |= AUDIO_AT_EOS;
1443 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001444 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001445 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001446}
1447
Andreas Huber6be780e2010-02-08 14:40:30 -08001448status_t AwesomePlayer::prepare() {
1449 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001450 return prepare_l();
1451}
Andreas Huber6be780e2010-02-08 14:40:30 -08001452
Andreas Huberffdf4782010-02-09 14:05:43 -08001453status_t AwesomePlayer::prepare_l() {
1454 if (mFlags & PREPARED) {
1455 return OK;
1456 }
1457
1458 if (mFlags & PREPARING) {
1459 return UNKNOWN_ERROR;
1460 }
1461
1462 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001463 status_t err = prepareAsync_l();
1464
1465 if (err != OK) {
1466 return err;
1467 }
1468
Andreas Huberffdf4782010-02-09 14:05:43 -08001469 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001470 mPreparedCondition.wait(mLock);
1471 }
1472
Andreas Huberffdf4782010-02-09 14:05:43 -08001473 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001474}
1475
1476status_t AwesomePlayer::prepareAsync() {
1477 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001478
1479 if (mFlags & PREPARING) {
1480 return UNKNOWN_ERROR; // async prepare already pending
1481 }
1482
1483 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001484 return prepareAsync_l();
1485}
1486
1487status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001488 if (mFlags & PREPARING) {
1489 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001490 }
1491
Andreas Huber406a18b2010-02-18 16:45:13 -08001492 if (!mQueueStarted) {
1493 mQueue.start();
1494 mQueueStarted = true;
1495 }
1496
Andreas Huberffdf4782010-02-09 14:05:43 -08001497 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001498 mAsyncPrepareEvent = new AwesomeEvent(
1499 this, &AwesomePlayer::onPrepareAsyncEvent);
1500
1501 mQueue.postEvent(mAsyncPrepareEvent);
1502
1503 return OK;
1504}
1505
Andreas Huberffdf4782010-02-09 14:05:43 -08001506status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001507 sp<DataSource> dataSource;
1508
1509 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001510 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001511
1512 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001513 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001514 mLock.lock();
1515
1516 if (err != OK) {
1517 mConnectingDataSource.clear();
1518
1519 LOGI("mConnectingDataSource->connect() returned %d", err);
1520 return err;
1521 }
1522
Andreas Huber4d61f602010-06-10 11:17:50 -07001523#if 0
1524 mCachedSource = new NuCachedSource2(
1525 new ThrottledSource(
1526 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1527#else
1528 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1529#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001530 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001531
1532 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001533 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1534 String8 uri("http://");
1535 uri.append(mUri.string() + 11);
1536
Andreas Huber54d09722010-10-12 11:34:37 -07001537 sp<LiveSource> liveSource = new LiveSource(uri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001538
Andreas Huber54d09722010-10-12 11:34:37 -07001539 mCachedSource = new NuCachedSource2(liveSource);
Andreas Huber4d61f602010-06-10 11:17:50 -07001540 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001541
1542 sp<MediaExtractor> extractor =
1543 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001544
Andreas Huber54d09722010-10-12 11:34:37 -07001545 static_cast<MPEG2TSExtractor *>(extractor.get())
1546 ->setLiveSource(liveSource);
1547
Andreas Huber4d61f602010-06-10 11:17:50 -07001548 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001549 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001550 if (mLooper == NULL) {
1551 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001552 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001553 mLooper->start(
1554 false /* runOnCallingThread */,
1555 false /* canCallJava */,
1556 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001557 }
1558
Mike Dodd8741dfa2010-08-12 16:04:35 -07001559 const char *startOfCodecString = &mUri.string()[13];
1560 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1561 if (startOfSlash1 == NULL) {
1562 return BAD_VALUE;
1563 }
1564 const char *startOfWidthString = &startOfSlash1[1];
1565 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1566 if (startOfSlash2 == NULL) {
1567 return BAD_VALUE;
1568 }
1569 const char *startOfHeightString = &startOfSlash2[1];
1570
1571 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1572 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1573 String8 heightString(startOfHeightString);
1574
Andreas Huber57648e42010-08-04 10:14:30 -07001575#if 0
1576 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1577 mLooper->registerHandler(mRTPPusher);
1578
1579 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1580 mLooper->registerHandler(mRTCPPusher);
1581#endif
1582
1583 mRTPSession = new ARTPSession;
1584 mLooper->registerHandler(mRTPSession);
1585
1586#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001587 // My AMR SDP
1588 static const char *raw =
1589 "v=0\r\n"
1590 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1591 "s=QuickTime\r\n"
1592 "t=0 0\r\n"
1593 "a=range:npt=0-315\r\n"
1594 "a=isma-compliance:2,2.0,2\r\n"
1595 "m=audio 5434 RTP/AVP 97\r\n"
1596 "c=IN IP4 127.0.0.1\r\n"
1597 "b=AS:30\r\n"
1598 "a=rtpmap:97 AMR/8000/1\r\n"
1599 "a=fmtp:97 octet-align\r\n";
1600#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001601 String8 sdp;
1602 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001603 "v=0\r\n"
1604 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1605 "s=QuickTime\r\n"
1606 "t=0 0\r\n"
1607 "a=range:npt=0-315\r\n"
1608 "a=isma-compliance:2,2.0,2\r\n"
1609 "m=video 5434 RTP/AVP 97\r\n"
1610 "c=IN IP4 127.0.0.1\r\n"
1611 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001612 "a=rtpmap:97 %s/90000\r\n"
1613 "a=cliprect:0,0,%s,%s\r\n"
1614 "a=framesize:97 %s-%s\r\n",
1615
1616 codecString.string(),
1617 heightString.string(), widthString.string(),
1618 widthString.string(), heightString.string()
1619 );
1620 const char *raw = sdp.string();
1621
Andreas Huber57648e42010-08-04 10:14:30 -07001622#endif
1623
1624 sp<ASessionDescription> desc = new ASessionDescription;
1625 CHECK(desc->setTo(raw, strlen(raw)));
1626
1627 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1628
1629 if (mRTPPusher != NULL) {
1630 mRTPPusher->start();
1631 }
1632
1633 if (mRTCPPusher != NULL) {
1634 mRTCPPusher->start();
1635 }
1636
1637 CHECK_EQ(mRTPSession->countTracks(), 1u);
1638 sp<MediaSource> source = mRTPSession->trackAt(0);
1639
1640#if 0
1641 bool eos;
1642 while (((APacketSource *)source.get())
1643 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1644 usleep(100000ll);
1645 }
1646#endif
1647
1648 const char *mime;
1649 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1650
1651 if (!strncasecmp("video/", mime, 6)) {
1652 setVideoSource(source);
1653 } else {
1654 CHECK(!strncasecmp("audio/", mime, 6));
1655 setAudioSource(source);
1656 }
1657
1658 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1659
1660 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001661 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1662 if (mLooper == NULL) {
1663 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001664 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001665 mLooper->start();
1666 }
1667 mRTSPController = new ARTSPController(mLooper);
1668 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001669
Andreas Huber7a747b82010-06-07 15:19:40 -07001670 LOGI("ARTSPController::connect returned %d", err);
1671
1672 if (err != OK) {
1673 mRTSPController.clear();
1674 return err;
1675 }
1676
1677 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001678 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001679 } else {
1680 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1681 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001682
1683 if (dataSource == NULL) {
1684 return UNKNOWN_ERROR;
1685 }
1686
1687 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1688
1689 if (extractor == NULL) {
1690 return UNKNOWN_ERROR;
1691 }
1692
Gloria Wangd5770912010-06-22 13:55:38 -07001693 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangc2c22e72010-11-01 15:53:16 -07001694 if (mDecryptHandle != NULL) {
1695 if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
1696 if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) {
1697 LOGD("Setting mCachedSource to NULL for WVM\n");
1698 mCachedSource.clear();
1699 }
1700 } else {
1701 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
1702 }
Gloria Wangd5770912010-06-22 13:55:38 -07001703 }
1704
Andreas Huberffdf4782010-02-09 14:05:43 -08001705 return setDataSource_l(extractor);
1706}
1707
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001708void AwesomePlayer::abortPrepare(status_t err) {
1709 CHECK(err != OK);
1710
1711 if (mIsAsyncPrepare) {
1712 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1713 }
1714
1715 mPrepareResult = err;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001716 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001717 mAsyncPrepareEvent = NULL;
1718 mPreparedCondition.broadcast();
1719}
1720
Andreas Huberf71daba2010-03-24 09:24:40 -07001721// static
1722bool AwesomePlayer::ContinuePreparation(void *cookie) {
1723 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1724
1725 return (me->mFlags & PREPARE_CANCELLED) == 0;
1726}
1727
Andreas Huber6be780e2010-02-08 14:40:30 -08001728void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001729 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001730
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001731 if (mFlags & PREPARE_CANCELLED) {
1732 LOGI("prepare was cancelled before doing anything");
1733 abortPrepare(UNKNOWN_ERROR);
1734 return;
1735 }
1736
1737 if (mUri.size() > 0) {
1738 status_t err = finishSetDataSource_l();
1739
1740 if (err != OK) {
1741 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001742 return;
1743 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001744 }
1745
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001746 if (mVideoTrack != NULL && mVideoSource == NULL) {
1747 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001748
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001749 if (err != OK) {
1750 abortPrepare(err);
1751 return;
1752 }
1753 }
1754
1755 if (mAudioTrack != NULL && mAudioSource == NULL) {
1756 status_t err = initAudioDecoder();
1757
1758 if (err != OK) {
1759 abortPrepare(err);
1760 return;
1761 }
1762 }
1763
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001764 mFlags |= PREPARING_CONNECTED;
1765
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001766 if (mCachedSource != NULL || mRTSPController != NULL) {
1767 postBufferingEvent_l();
1768 } else {
1769 finishAsyncPrepare_l();
1770 }
1771}
1772
1773void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001774 if (mIsAsyncPrepare) {
Andreas Hubere3c01832010-08-16 08:49:37 -07001775 if (mVideoSource == NULL) {
Andreas Huberffdf4782010-02-09 14:05:43 -08001776 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1777 } else {
Andreas Hubere3c01832010-08-16 08:49:37 -07001778 notifyVideoSize_l();
Andreas Huberffdf4782010-02-09 14:05:43 -08001779 }
1780
1781 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001782 }
1783
Andreas Huberffdf4782010-02-09 14:05:43 -08001784 mPrepareResult = OK;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001785 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001786 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001787 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001788 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001789}
1790
Andreas Huberba7ec912010-02-12 10:42:02 -08001791status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001792 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001793 Mutex::Autolock autoLock(mLock);
1794
1795 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001796 if (mLastVideoBuffer == NULL) {
1797 //go into here if video is suspended again
1798 //after resuming without being played between
1799 //them
1800 SuspensionState *state = mSuspensionState;
1801 mSuspensionState = NULL;
1802 reset_l();
1803 mSuspensionState = state;
1804 return OK;
1805 }
1806
1807 delete mSuspensionState;
1808 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001809 }
1810
Andreas Huberedbb4d82010-03-12 08:59:22 -08001811 if (mFlags & PREPARING) {
1812 mFlags |= PREPARE_CANCELLED;
1813 if (mConnectingDataSource != NULL) {
1814 LOGI("interrupting the connection process");
1815 mConnectingDataSource->disconnect();
1816 }
1817 }
1818
Andreas Huberba7ec912010-02-12 10:42:02 -08001819 while (mFlags & PREPARING) {
1820 mPreparedCondition.wait(mLock);
1821 }
1822
1823 SuspensionState *state = new SuspensionState;
1824 state->mUri = mUri;
1825 state->mUriHeaders = mUriHeaders;
1826 state->mFileSource = mFileSource;
1827
Andreas Huber9fee0b22010-09-03 14:09:21 -07001828 state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001829 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001830
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001831 if (mLastVideoBuffer) {
1832 size_t size = mLastVideoBuffer->range_length();
Andreas Huber1e194162010-10-06 16:43:57 -07001833
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001834 if (size) {
Andreas Huber1e194162010-10-06 16:43:57 -07001835 int32_t unreadable;
1836 if (!mLastVideoBuffer->meta_data()->findInt32(
1837 kKeyIsUnreadable, &unreadable)
1838 || unreadable == 0) {
1839 state->mLastVideoFrameSize = size;
1840 state->mLastVideoFrame = malloc(size);
1841 memcpy(state->mLastVideoFrame,
1842 (const uint8_t *)mLastVideoBuffer->data()
1843 + mLastVideoBuffer->range_offset(),
1844 size);
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001845
Andreas Huber1e194162010-10-06 16:43:57 -07001846 state->mVideoWidth = mVideoWidth;
1847 state->mVideoHeight = mVideoHeight;
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001848
Andreas Huber1e194162010-10-06 16:43:57 -07001849 sp<MetaData> meta = mVideoSource->getFormat();
1850 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1851 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1852 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1853 } else {
1854 LOGV("Unable to save last video frame, we have no access to "
1855 "the decoded video data.");
1856 }
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001857 }
1858 }
1859
Andreas Huberba7ec912010-02-12 10:42:02 -08001860 reset_l();
1861
1862 mSuspensionState = state;
1863
1864 return OK;
1865}
1866
1867status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001868 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001869 Mutex::Autolock autoLock(mLock);
1870
1871 if (mSuspensionState == NULL) {
1872 return INVALID_OPERATION;
1873 }
1874
1875 SuspensionState *state = mSuspensionState;
1876 mSuspensionState = NULL;
1877
1878 status_t err;
1879 if (state->mFileSource != NULL) {
1880 err = setDataSource_l(state->mFileSource);
1881
1882 if (err == OK) {
1883 mFileSource = state->mFileSource;
1884 }
1885 } else {
1886 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1887 }
1888
1889 if (err != OK) {
1890 delete state;
1891 state = NULL;
1892
1893 return err;
1894 }
1895
1896 seekTo_l(state->mPositionUs);
1897
Andreas Huber9fee0b22010-09-03 14:09:21 -07001898 mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001899
Andreas Hubere3c01832010-08-16 08:49:37 -07001900 if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001901 mVideoRenderer =
1902 new AwesomeLocalRenderer(
1903 true, // previewOnly
1904 "",
1905 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1906 mISurface,
Andreas Hubere3c01832010-08-16 08:49:37 -07001907 mSurface,
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001908 state->mVideoWidth,
1909 state->mVideoHeight,
1910 state->mDecodedWidth,
1911 state->mDecodedHeight);
1912
1913 mVideoRendererIsPreview = true;
1914
1915 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1916 state->mLastVideoFrame, state->mLastVideoFrameSize);
1917 }
1918
Andreas Huberba7ec912010-02-12 10:42:02 -08001919 if (state->mFlags & PLAYING) {
1920 play_l();
1921 }
1922
Gloria Wangb19da8e2010-04-12 17:13:06 -07001923 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001924 state = NULL;
1925
1926 return OK;
1927}
1928
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001929uint32_t AwesomePlayer::flags() const {
1930 return mExtractorFlags;
1931}
1932
Andreas Huber2b359ed2010-09-28 11:56:39 -07001933void AwesomePlayer::postAudioEOS() {
1934 postCheckAudioStatusEvent_l();
1935}
1936
1937void AwesomePlayer::postAudioSeekComplete() {
1938 postCheckAudioStatusEvent_l();
1939}
1940
Andreas Huber27366fc2009-11-20 09:32:46 -08001941} // namespace android