blob: 4e1969bc437c8fcabd766b5943113396f2361de5 [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 Huber27366fc2009-11-20 09:32:46 -080052namespace android {
53
Andreas Huber87ab9cd2010-09-03 13:20:33 -070054static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
55static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
56
Andreas Huber27366fc2009-11-20 09:32:46 -080057struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080058 AwesomeEvent(
59 AwesomePlayer *player,
60 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080061 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080062 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080063 }
64
65protected:
66 virtual ~AwesomeEvent() {}
67
68 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080069 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080070 }
71
72private:
73 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080074 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080075
76 AwesomeEvent(const AwesomeEvent &);
77 AwesomeEvent &operator=(const AwesomeEvent &);
78};
79
Andreas Huber1314e732009-12-14 14:18:22 -080080struct AwesomeRemoteRenderer : public AwesomeRenderer {
81 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
82 : mTarget(target) {
83 }
84
85 virtual void render(MediaBuffer *buffer) {
86 void *id;
87 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
88 mTarget->render((IOMX::buffer_id)id);
89 }
90 }
91
92private:
93 sp<IOMXRenderer> mTarget;
94
95 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
96 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
97};
98
99struct AwesomeLocalRenderer : public AwesomeRenderer {
100 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800101 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800102 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -0800103 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700104 const sp<ISurface> &isurface,
105 const sp<Surface> &surface,
Andreas Huber1314e732009-12-14 14:18:22 -0800106 size_t displayWidth, size_t displayHeight,
107 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800108 : mTarget(NULL),
109 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800110 init(previewOnly, componentName,
Andreas Hubere3c01832010-08-16 08:49:37 -0700111 colorFormat, isurface, surface, displayWidth,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800112 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800113 }
114
115 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800116 render((const uint8_t *)buffer->data() + buffer->range_offset(),
117 buffer->range_length());
118 }
119
120 void render(const void *data, size_t size) {
121 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800122 }
123
124protected:
125 virtual ~AwesomeLocalRenderer() {
126 delete mTarget;
127 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800128
129 if (mLibHandle) {
130 dlclose(mLibHandle);
131 mLibHandle = NULL;
132 }
Andreas Huber1314e732009-12-14 14:18:22 -0800133 }
134
135private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800136 VideoRenderer *mTarget;
137 void *mLibHandle;
138
139 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800140 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800141 const char *componentName,
142 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700143 const sp<ISurface> &isurface,
144 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800145 size_t displayWidth, size_t displayHeight,
146 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800147
148 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
149 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
150};
151
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800152void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800153 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800154 const char *componentName,
155 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700156 const sp<ISurface> &isurface,
157 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800158 size_t displayWidth, size_t displayHeight,
159 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800160 if (!previewOnly) {
161 // We will stick to the vanilla software-color-converting renderer
162 // for "previewOnly" mode, to avoid unneccessarily switching overlays
163 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800164
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800165 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800166
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800167 if (mLibHandle) {
168 typedef VideoRenderer *(*CreateRendererFunc)(
169 const sp<ISurface> &surface,
170 const char *componentName,
171 OMX_COLOR_FORMATTYPE colorFormat,
172 size_t displayWidth, size_t displayHeight,
173 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800174
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800175 CreateRendererFunc func =
176 (CreateRendererFunc)dlsym(
177 mLibHandle,
178 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
179 "OMX_COLOR_FORMATTYPEjjjj");
180
181 if (func) {
182 mTarget =
Andreas Hubere3c01832010-08-16 08:49:37 -0700183 (*func)(isurface, componentName, colorFormat,
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800184 displayWidth, displayHeight,
185 decodedWidth, decodedHeight);
186 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800187 }
188 }
189
190 if (mTarget == NULL) {
191 mTarget = new SoftwareRenderer(
192 colorFormat, surface, displayWidth, displayHeight,
193 decodedWidth, decodedHeight);
194 }
195}
196
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700197struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
198 AwesomeNativeWindowRenderer(const sp<ANativeWindow> &nativeWindow)
199 : mNativeWindow(nativeWindow) {
200 }
201
202 virtual void render(MediaBuffer *buffer) {
203 status_t err = mNativeWindow->queueBuffer(
204 mNativeWindow.get(), buffer->graphicBuffer().get());
205 if (err != 0) {
206 LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
207 -err);
208 return;
209 }
210
211 sp<MetaData> metaData = buffer->meta_data();
212 metaData->setInt32(kKeyRendered, 1);
213 }
214
215protected:
216 virtual ~AwesomeNativeWindowRenderer() {}
217
218private:
219 sp<ANativeWindow> mNativeWindow;
220
221 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
222 AwesomeNativeWindowRenderer &operator=(
223 const AwesomeNativeWindowRenderer &);
224};
225
Andreas Huber27366fc2009-11-20 09:32:46 -0800226AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800227 : mQueueStarted(false),
228 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800229 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800230 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800231 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700232 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800233 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800234 mVideoBuffer(NULL),
Gloria Wangd5770912010-06-22 13:55:38 -0700235 mSuspensionState(NULL),
236 mDecryptHandle(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800237 CHECK_EQ(mClient.connect(), OK);
238
239 DataSource::RegisterDefaultSniffers();
240
Andreas Huber6be780e2010-02-08 14:40:30 -0800241 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800242 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800243 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800244 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800245 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800246 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800247
248 mCheckAudioStatusEvent = new AwesomeEvent(
249 this, &AwesomePlayer::onCheckAudioStatus);
250
Andreas Huber70d10c02010-02-03 11:37:29 -0800251 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800252
Andreas Huber27366fc2009-11-20 09:32:46 -0800253 reset();
254}
255
256AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800257 if (mQueueStarted) {
258 mQueue.stop();
259 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800260
261 reset();
262
263 mClient.disconnect();
264}
265
Andreas Huberb9e63832010-01-26 16:20:10 -0800266void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800267 mQueue.cancelEvent(mVideoEvent->eventID());
268 mVideoEventPending = false;
269 mQueue.cancelEvent(mStreamDoneEvent->eventID());
270 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800271 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
272 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800273
274 if (!keepBufferingGoing) {
275 mQueue.cancelEvent(mBufferingEvent->eventID());
276 mBufferingEventPending = false;
277 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800278}
279
Andreas Hubera3f43842010-01-21 10:28:45 -0800280void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800281 Mutex::Autolock autoLock(mLock);
282 mListener = listener;
283}
284
Andreas Huber433c9ac2010-01-27 16:49:05 -0800285status_t AwesomePlayer::setDataSource(
286 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800287 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800288 return setDataSource_l(uri, headers);
289}
Andreas Huber27366fc2009-11-20 09:32:46 -0800290
Andreas Huberba7ec912010-02-12 10:42:02 -0800291status_t AwesomePlayer::setDataSource_l(
292 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800293 reset_l();
294
Andreas Huberffdf4782010-02-09 14:05:43 -0800295 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800296
Andreas Huberffdf4782010-02-09 14:05:43 -0800297 if (headers) {
298 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800299 }
300
Andreas Huberffdf4782010-02-09 14:05:43 -0800301 // The actual work will be done during preparation in the call to
302 // ::finishSetDataSource_l to avoid blocking the calling thread in
303 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800304
Andreas Huberffdf4782010-02-09 14:05:43 -0800305 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800306}
307
308status_t AwesomePlayer::setDataSource(
309 int fd, int64_t offset, int64_t length) {
310 Mutex::Autolock autoLock(mLock);
311
312 reset_l();
313
Andreas Huberba7ec912010-02-12 10:42:02 -0800314 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800315
Andreas Huberba7ec912010-02-12 10:42:02 -0800316 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800317
318 if (err != OK) {
319 return err;
320 }
321
Andreas Huberba7ec912010-02-12 10:42:02 -0800322 mFileSource = dataSource;
323
324 return setDataSource_l(dataSource);
325}
326
327status_t AwesomePlayer::setDataSource_l(
328 const sp<DataSource> &dataSource) {
329 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800330
331 if (extractor == NULL) {
332 return UNKNOWN_ERROR;
333 }
334
Gloria Wangd5770912010-06-22 13:55:38 -0700335 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangeab18ea2010-10-29 10:09:47 -0700336 if (mDecryptHandle != NULL
337 && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
338 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
Gloria Wangd5770912010-06-22 13:55:38 -0700339 }
340
Andreas Huber27366fc2009-11-20 09:32:46 -0800341 return setDataSource_l(extractor);
342}
343
344status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700345 // Attempt to approximate overall stream bitrate by summing all
346 // tracks' individual bitrates, if not all of them advertise bitrate,
347 // we have to fail.
348
349 int64_t totalBitRate = 0;
350
351 for (size_t i = 0; i < extractor->countTracks(); ++i) {
352 sp<MetaData> meta = extractor->getTrackMetaData(i);
353
354 int32_t bitrate;
355 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
356 totalBitRate = -1;
357 break;
358 }
359
360 totalBitRate += bitrate;
361 }
362
363 mBitrate = totalBitRate;
364
365 LOGV("mBitrate = %lld bits/sec", mBitrate);
366
Andreas Huber27366fc2009-11-20 09:32:46 -0800367 bool haveAudio = false;
368 bool haveVideo = false;
369 for (size_t i = 0; i < extractor->countTracks(); ++i) {
370 sp<MetaData> meta = extractor->getTrackMetaData(i);
371
372 const char *mime;
373 CHECK(meta->findCString(kKeyMIMEType, &mime));
374
375 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800376 setVideoSource(extractor->getTrack(i));
377 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800378 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800379 setAudioSource(extractor->getTrack(i));
380 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700381
Andreas Huber1913c1a2010-10-04 11:09:31 -0700382 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
383 // Only do this for vorbis audio, none of the other audio
384 // formats even support this ringtone specific hack and
385 // retrieving the metadata on some extractors may turn out
386 // to be very expensive.
387 sp<MetaData> fileMeta = extractor->getMetaData();
388 int32_t loop;
389 if (fileMeta != NULL
390 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
391 mFlags |= AUTO_LOOPING;
392 }
Andreas Huber9fee0b22010-09-03 14:09:21 -0700393 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800394 }
395
396 if (haveAudio && haveVideo) {
397 break;
398 }
399 }
400
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700401 if (!haveAudio && !haveVideo) {
402 return UNKNOWN_ERROR;
403 }
404
405 mExtractorFlags = extractor->flags();
406
407 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800408}
409
410void AwesomePlayer::reset() {
411 Mutex::Autolock autoLock(mLock);
412 reset_l();
413}
414
415void AwesomePlayer::reset_l() {
Gloria Wangd5770912010-06-22 13:55:38 -0700416 if (mDecryptHandle != NULL) {
417 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
418 Playback::STOP, 0);
Gloria Wangc2c22e72010-11-01 15:53:16 -0700419 mDrmManagerClient->closeDecryptSession(mDecryptHandle);
Gloria Wangd5770912010-06-22 13:55:38 -0700420 mDecryptHandle = NULL;
421 mDrmManagerClient = NULL;
422 }
423
Andreas Huberedbb4d82010-03-12 08:59:22 -0800424 if (mFlags & PREPARING) {
425 mFlags |= PREPARE_CANCELLED;
426 if (mConnectingDataSource != NULL) {
427 LOGI("interrupting the connection process");
428 mConnectingDataSource->disconnect();
429 }
Andreas Hubereaf2c5a2010-10-19 12:18:51 -0700430
431 if (mFlags & PREPARING_CONNECTED) {
432 // We are basically done preparing, we're just buffering
433 // enough data to start playback, we can safely interrupt that.
434 finishAsyncPrepare_l();
435 }
Andreas Huberedbb4d82010-03-12 08:59:22 -0800436 }
437
Andreas Huberffdf4782010-02-09 14:05:43 -0800438 while (mFlags & PREPARING) {
439 mPreparedCondition.wait(mLock);
440 }
441
Andreas Huber27366fc2009-11-20 09:32:46 -0800442 cancelPlayerEvents();
443
Andreas Huber4d61f602010-06-10 11:17:50 -0700444 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800445 mAudioTrack.clear();
446 mVideoTrack.clear();
447
Andreas Huberba7ec912010-02-12 10:42:02 -0800448 // Shutdown audio first, so that the respone to the reset request
449 // appears to happen instantaneously as far as the user is concerned
450 // If we did this later, audio would continue playing while we
451 // shutdown the video-related resources and the player appear to
452 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800453 if (mAudioPlayer == NULL && mAudioSource != NULL) {
454 // If we had an audio player, it would have effectively
455 // taken possession of the audio source and stopped it when
456 // _it_ is stopped. Otherwise this is still our responsibility.
457 mAudioSource->stop();
458 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800459 mAudioSource.clear();
460
Andreas Huberba7ec912010-02-12 10:42:02 -0800461 mTimeSource = NULL;
462
463 delete mAudioPlayer;
464 mAudioPlayer = NULL;
465
Andreas Huber3522b5a52010-01-22 14:36:53 -0800466 mVideoRenderer.clear();
467
Andreas Huber27366fc2009-11-20 09:32:46 -0800468 if (mLastVideoBuffer) {
469 mLastVideoBuffer->release();
470 mLastVideoBuffer = NULL;
471 }
472
473 if (mVideoBuffer) {
474 mVideoBuffer->release();
475 mVideoBuffer = NULL;
476 }
477
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700478 if (mRTSPController != NULL) {
479 mRTSPController->disconnect();
480 mRTSPController.clear();
481 }
482
Andreas Huber57648e42010-08-04 10:14:30 -0700483 mRTPPusher.clear();
484 mRTCPPusher.clear();
485 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700486
Andreas Huber27366fc2009-11-20 09:32:46 -0800487 if (mVideoSource != NULL) {
488 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800489
490 // The following hack is necessary to ensure that the OMX
491 // component is completely released by the time we may try
492 // to instantiate it again.
493 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800494 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800495 while (tmp.promote() != NULL) {
496 usleep(1000);
497 }
498 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800499 }
500
Andreas Huber27366fc2009-11-20 09:32:46 -0800501 mDurationUs = -1;
502 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700503 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800504 mVideoWidth = mVideoHeight = -1;
505 mTimeSourceDeltaUs = 0;
506 mVideoTimeUs = 0;
507
508 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700509 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800510 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800511
Andreas Huberffdf4782010-02-09 14:05:43 -0800512 mUri.setTo("");
513 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800514
515 mFileSource.clear();
516
517 delete mSuspensionState;
518 mSuspensionState = NULL;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700519
520 mBitrate = -1;
Andreas Huber27366fc2009-11-20 09:32:46 -0800521}
522
Andreas Huber6be780e2010-02-08 14:40:30 -0800523void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800524 if (mListener != NULL) {
525 sp<MediaPlayerBase> listener = mListener.promote();
526
527 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800528 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800529 }
530 }
531}
532
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700533bool AwesomePlayer::getBitrate(int64_t *bitrate) {
534 off_t size;
535 if (mDurationUs >= 0 && mCachedSource != NULL
536 && mCachedSource->getSize(&size) == OK) {
537 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
538 return true;
539 }
540
541 if (mBitrate >= 0) {
542 *bitrate = mBitrate;
543 return true;
544 }
545
546 *bitrate = 0;
547
548 return false;
549}
550
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700551// Returns true iff cached duration is available/applicable.
552bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700553 int64_t bitrate;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700554
555 if (mRTSPController != NULL) {
556 *durationUs = mRTSPController->getQueueDurationUs(eos);
557 return true;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700558 } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700559 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
560 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
561 return true;
562 }
563
564 return false;
565}
566
Andreas Huberb9e63832010-01-26 16:20:10 -0800567void AwesomePlayer::onBufferingUpdate() {
568 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800569 if (!mBufferingEventPending) {
570 return;
571 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800572 mBufferingEventPending = false;
573
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700574 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700575 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700576 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700577
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700578 if (eos) {
579 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700580 if (mFlags & PREPARING) {
581 LOGV("cache has reached EOS, prepare is done.");
582 finishAsyncPrepare_l();
583 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700584 } else {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700585 int64_t bitrate;
586 if (getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700587 size_t cachedSize = mCachedSource->cachedSize();
588 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
589
590 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
591 if (percentage > 100) {
592 percentage = 100;
593 }
594
595 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
596 } else {
597 // We don't know the bitrate of the stream, use absolute size
598 // limits to maintain the cache.
599
Andreas Huber54d09722010-10-12 11:34:37 -0700600 const size_t kLowWaterMarkBytes = 40000;
601 const size_t kHighWaterMarkBytes = 200000;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700602
603 if ((mFlags & PLAYING) && !eos
604 && (cachedDataRemaining < kLowWaterMarkBytes)) {
605 LOGI("cache is running low (< %d) , pausing.",
606 kLowWaterMarkBytes);
607 mFlags |= CACHE_UNDERRUN;
608 pause_l();
609 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
610 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
611 if (mFlags & CACHE_UNDERRUN) {
612 LOGI("cache has filled up (> %d), resuming.",
613 kHighWaterMarkBytes);
614 mFlags &= ~CACHE_UNDERRUN;
615 play_l();
616 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
617 } else if (mFlags & PREPARING) {
618 LOGV("cache has filled up (> %d), prepare is done",
619 kHighWaterMarkBytes);
620 finishAsyncPrepare_l();
621 }
622 }
623 }
624 }
625 }
626
627 int64_t cachedDurationUs;
628 bool eos;
629 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700630 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700631 && (cachedDurationUs < kLowWaterMarkUs)) {
632 LOGI("cache is running low (%.2f secs) , pausing.",
633 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700634 mFlags |= CACHE_UNDERRUN;
635 pause_l();
636 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700637 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
638 if (mFlags & CACHE_UNDERRUN) {
639 LOGI("cache has filled up (%.2f secs), resuming.",
640 cachedDurationUs / 1E6);
641 mFlags &= ~CACHE_UNDERRUN;
642 play_l();
643 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
644 } else if (mFlags & PREPARING) {
645 LOGV("cache has filled up (%.2f secs), prepare is done",
646 cachedDurationUs / 1E6);
647 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700648 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700649 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800650 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700651
Andreas Huber4d61f602010-06-10 11:17:50 -0700652 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800653}
654
Andreas Huber4c19bf92010-09-08 14:32:20 -0700655void AwesomePlayer::partial_reset_l() {
656 // Only reset the video renderer and shut down the video decoder.
657 // Then instantiate a new video decoder and resume video playback.
658
659 mVideoRenderer.clear();
660
661 if (mLastVideoBuffer) {
662 mLastVideoBuffer->release();
663 mLastVideoBuffer = NULL;
664 }
665
666 if (mVideoBuffer) {
667 mVideoBuffer->release();
668 mVideoBuffer = NULL;
669 }
670
671 {
672 mVideoSource->stop();
673
674 // The following hack is necessary to ensure that the OMX
675 // component is completely released by the time we may try
676 // to instantiate it again.
677 wp<MediaSource> tmp = mVideoSource;
678 mVideoSource.clear();
679 while (tmp.promote() != NULL) {
680 usleep(1000);
681 }
682 IPCThreadState::self()->flushCommands();
683 }
684
685 CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
686}
687
Andreas Huber27366fc2009-11-20 09:32:46 -0800688void AwesomePlayer::onStreamDone() {
689 // Posted whenever any stream finishes playing.
690
691 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800692 if (!mStreamDoneEventPending) {
693 return;
694 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800695 mStreamDoneEventPending = false;
696
Andreas Huber4c19bf92010-09-08 14:32:20 -0700697 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
698 // This special status is returned because an http live stream's
699 // video stream switched to a different bandwidth at this point
700 // and future data may have been encoded using different parameters.
701 // This requires us to shutdown the video decoder and reinstantiate
702 // a fresh one.
703
704 LOGV("INFO_DISCONTINUITY");
705
706 CHECK(mVideoSource != NULL);
707
708 partial_reset_l();
709 postVideoEvent_l();
710 return;
711 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700712 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
713
714 notifyListener_l(
715 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
716
Andreas Huberc743f452010-10-05 10:25:34 -0700717 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700718
719 mFlags |= AT_EOS;
720 return;
721 }
722
723 const bool allDone =
724 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
725 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
726
727 if (!allDone) {
728 return;
729 }
730
Andreas Huber9fee0b22010-09-03 14:09:21 -0700731 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800732 seekTo_l(0);
733
Andreas Huber7085b6842010-02-03 16:02:02 -0800734 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800735 postVideoEvent_l();
736 }
737 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700738 LOGV("MEDIA_PLAYBACK_COMPLETE");
739 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800740
Andreas Huberc743f452010-10-05 10:25:34 -0700741 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800742
743 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800744 }
745}
746
747status_t AwesomePlayer::play() {
748 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700749
750 mFlags &= ~CACHE_UNDERRUN;
751
Andreas Huberba7ec912010-02-12 10:42:02 -0800752 return play_l();
753}
Andreas Huber27366fc2009-11-20 09:32:46 -0800754
Andreas Huberba7ec912010-02-12 10:42:02 -0800755status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800756 if (mFlags & PLAYING) {
757 return OK;
758 }
759
Andreas Huberffdf4782010-02-09 14:05:43 -0800760 if (!(mFlags & PREPARED)) {
761 status_t err = prepare_l();
762
763 if (err != OK) {
764 return err;
765 }
766 }
767
Andreas Huber27366fc2009-11-20 09:32:46 -0800768 mFlags |= PLAYING;
769 mFlags |= FIRST_FRAME;
770
Andreas Huberc1d5c922009-12-10 15:49:04 -0800771 bool deferredAudioSeek = false;
772
Andreas Huber27366fc2009-11-20 09:32:46 -0800773 if (mAudioSource != NULL) {
774 if (mAudioPlayer == NULL) {
775 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700776 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800777 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800778
779 // We've already started the MediaSource in order to enable
780 // the prefetcher to read its data.
781 status_t err = mAudioPlayer->start(
782 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800783
784 if (err != OK) {
785 delete mAudioPlayer;
786 mAudioPlayer = NULL;
787
788 mFlags &= ~(PLAYING | FIRST_FRAME);
789
790 return err;
791 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800792
Andreas Huber27366fc2009-11-20 09:32:46 -0800793 mTimeSource = mAudioPlayer;
794
Andreas Huberc1d5c922009-12-10 15:49:04 -0800795 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800796
797 mWatchForAudioSeekComplete = false;
798 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800799 }
800 } else {
801 mAudioPlayer->resume();
802 }
803 }
804
805 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700806 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800807 }
808
809 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800810 // Kick off video playback
811 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800812 }
813
Andreas Huberc1d5c922009-12-10 15:49:04 -0800814 if (deferredAudioSeek) {
815 // If there was a seek request while we were paused
816 // and we're just starting up again, honor the request now.
817 seekAudioIfNecessary_l();
818 }
819
Andreas Huber406a18b2010-02-18 16:45:13 -0800820 if (mFlags & AT_EOS) {
821 // Legacy behaviour, if a stream finishes playing and then
822 // is started again, we play from the start...
823 seekTo_l(0);
824 }
825
Gloria Wangd5770912010-06-22 13:55:38 -0700826 if (mDecryptHandle != NULL) {
827 int64_t position;
828 getPosition(&position);
829 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
830 Playback::START, position / 1000);
831 }
832
Andreas Huber27366fc2009-11-20 09:32:46 -0800833 return OK;
834}
835
Andreas Hubere3c01832010-08-16 08:49:37 -0700836void AwesomePlayer::notifyVideoSize_l() {
837 sp<MetaData> meta = mVideoSource->getFormat();
838
839 int32_t decodedWidth, decodedHeight;
840 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
841 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
842
843 notifyListener_l(MEDIA_SET_VIDEO_SIZE, decodedWidth, decodedHeight);
844}
845
Andreas Huber27366fc2009-11-20 09:32:46 -0800846void AwesomePlayer::initRenderer_l() {
Andreas Hubere3c01832010-08-16 08:49:37 -0700847 if (mSurface != NULL || mISurface != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800848 sp<MetaData> meta = mVideoSource->getFormat();
849
850 int32_t format;
851 const char *component;
852 int32_t decodedWidth, decodedHeight;
853 CHECK(meta->findInt32(kKeyColorFormat, &format));
854 CHECK(meta->findCString(kKeyDecoderComponent, &component));
855 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
856 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
857
Andreas Hubera67d5382009-12-10 15:32:12 -0800858 mVideoRenderer.clear();
859
860 // Must ensure that mVideoRenderer's destructor is actually executed
861 // before creating a new one.
862 IPCThreadState::self()->flushCommands();
863
Andreas Hubere3c01832010-08-16 08:49:37 -0700864 if (mSurface != NULL) {
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700865 if (strncmp(component, "OMX.", 4) == 0) {
866 // Hardware decoders avoid the CPU color conversion by decoding
867 // directly to ANativeBuffers, so we must use a renderer that
868 // just pushes those buffers to the ANativeWindow.
869 mVideoRenderer = new AwesomeNativeWindowRenderer(mSurface);
870 } else {
871 // Other decoders are instantiated locally and as a consequence
872 // allocate their buffers in local address space. This renderer
873 // then performs a color conversion and copy to get the data
874 // into the ANativeBuffer.
875 mVideoRenderer = new AwesomeLocalRenderer(
876 false, // previewOnly
877 component,
878 (OMX_COLOR_FORMATTYPE)format,
879 mISurface,
880 mSurface,
881 mVideoWidth, mVideoHeight,
882 decodedWidth, decodedHeight);
883 }
Andreas Hubere3c01832010-08-16 08:49:37 -0700884 } else {
Andreas Huber1314e732009-12-14 14:18:22 -0800885 // Our OMX codecs allocate buffers on the media_server side
886 // therefore they require a remote IOMXRenderer that knows how
887 // to display them.
888 mVideoRenderer = new AwesomeRemoteRenderer(
889 mClient.interface()->createRenderer(
890 mISurface, component,
891 (OMX_COLOR_FORMATTYPE)format,
892 decodedWidth, decodedHeight,
893 mVideoWidth, mVideoHeight));
Andreas Huber1314e732009-12-14 14:18:22 -0800894 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800895 }
896}
897
898status_t AwesomePlayer::pause() {
899 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700900
901 mFlags &= ~CACHE_UNDERRUN;
902
Andreas Huber27366fc2009-11-20 09:32:46 -0800903 return pause_l();
904}
905
Andreas Huberc743f452010-10-05 10:25:34 -0700906status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800907 if (!(mFlags & PLAYING)) {
908 return OK;
909 }
910
Andreas Huberb9e63832010-01-26 16:20:10 -0800911 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800912
913 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -0700914 if (at_eos) {
915 // If we played the audio stream to completion we
916 // want to make sure that all samples remaining in the audio
917 // track's queue are played out.
918 mAudioPlayer->pause(true /* playPendingSamples */);
919 } else {
920 mAudioPlayer->pause();
921 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800922 }
923
924 mFlags &= ~PLAYING;
925
Gloria Wangd5770912010-06-22 13:55:38 -0700926 if (mDecryptHandle != NULL) {
927 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
928 Playback::PAUSE, 0);
929 }
930
Andreas Huber27366fc2009-11-20 09:32:46 -0800931 return OK;
932}
933
934bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700935 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800936}
937
938void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
939 Mutex::Autolock autoLock(mLock);
940
941 mISurface = isurface;
942}
943
Andreas Hubere3c01832010-08-16 08:49:37 -0700944void AwesomePlayer::setSurface(const sp<Surface> &surface) {
945 Mutex::Autolock autoLock(mLock);
946
947 mSurface = surface;
948}
949
Andreas Huber27366fc2009-11-20 09:32:46 -0800950void AwesomePlayer::setAudioSink(
951 const sp<MediaPlayerBase::AudioSink> &audioSink) {
952 Mutex::Autolock autoLock(mLock);
953
954 mAudioSink = audioSink;
955}
956
957status_t AwesomePlayer::setLooping(bool shouldLoop) {
958 Mutex::Autolock autoLock(mLock);
959
960 mFlags = mFlags & ~LOOPING;
961
962 if (shouldLoop) {
963 mFlags |= LOOPING;
964 }
965
966 return OK;
967}
968
969status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700970 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800971
972 if (mDurationUs < 0) {
973 return UNKNOWN_ERROR;
974 }
975
976 *durationUs = mDurationUs;
977
978 return OK;
979}
980
981status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -0700982 if (mRTSPController != NULL) {
983 *positionUs = mRTSPController->getNormalPlayTimeUs();
984 }
985 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700986 *positionUs = mSeekTimeUs;
987 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700988 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800989 *positionUs = mVideoTimeUs;
990 } else if (mAudioPlayer != NULL) {
991 *positionUs = mAudioPlayer->getMediaTimeUs();
992 } else {
993 *positionUs = 0;
994 }
995
996 return OK;
997}
998
999status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -07001000 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001001 Mutex::Autolock autoLock(mLock);
1002 return seekTo_l(timeUs);
1003 }
1004
1005 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -08001006}
1007
Andreas Huber0c46b692010-10-08 15:21:08 -07001008// static
1009void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
1010 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
1011}
1012
1013void AwesomePlayer::onRTSPSeekDone() {
1014 notifyListener_l(MEDIA_SEEK_COMPLETE);
1015 mSeekNotificationSent = true;
1016}
1017
Andreas Huber27366fc2009-11-20 09:32:46 -08001018status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001019 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -07001020 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001021 return OK;
1022 }
1023
Andreas Huber4d61f602010-06-10 11:17:50 -07001024 if (mFlags & CACHE_UNDERRUN) {
1025 mFlags &= ~CACHE_UNDERRUN;
1026 play_l();
1027 }
1028
Andreas Huber27366fc2009-11-20 09:32:46 -08001029 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001030 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001031 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001032 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -08001033
1034 seekAudioIfNecessary_l();
1035
Andreas Huber8e2b9412010-03-31 09:40:15 -07001036 if (!(mFlags & PLAYING)) {
1037 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1038 " immediately.");
1039
1040 notifyListener_l(MEDIA_SEEK_COMPLETE);
1041 mSeekNotificationSent = true;
1042 }
1043
Andreas Huber27366fc2009-11-20 09:32:46 -08001044 return OK;
1045}
1046
1047void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -08001048 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001049 mAudioPlayer->seekTo(mSeekTimeUs);
1050
Andreas Huber70d10c02010-02-03 11:37:29 -08001051 mWatchForAudioSeekComplete = true;
1052 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001053 mSeekNotificationSent = false;
Gloria Wangd5770912010-06-22 13:55:38 -07001054
1055 if (mDecryptHandle != NULL) {
1056 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1057 Playback::PAUSE, 0);
1058 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1059 Playback::START, mSeekTimeUs / 1000);
1060 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001061 }
1062}
1063
1064status_t AwesomePlayer::getVideoDimensions(
1065 int32_t *width, int32_t *height) const {
1066 Mutex::Autolock autoLock(mLock);
1067
1068 if (mVideoWidth < 0 || mVideoHeight < 0) {
1069 return UNKNOWN_ERROR;
1070 }
1071
1072 *width = mVideoWidth;
1073 *height = mVideoHeight;
1074
1075 return OK;
1076}
1077
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001078void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1079 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001080
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001081 mAudioTrack = source;
1082}
1083
1084status_t AwesomePlayer::initAudioDecoder() {
1085 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -08001086
1087 const char *mime;
1088 CHECK(meta->findCString(kKeyMIMEType, &mime));
1089
1090 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001091 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -08001092 } else {
1093 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001094 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -08001095 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001096 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -08001097 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001098
1099 if (mAudioSource != NULL) {
1100 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001101 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001102 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001103 if (mDurationUs < 0 || durationUs > mDurationUs) {
1104 mDurationUs = durationUs;
1105 }
1106 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001107
Andreas Huber3c78a1b2010-05-13 09:15:21 -07001108 status_t err = mAudioSource->start();
1109
1110 if (err != OK) {
1111 mAudioSource.clear();
1112 return err;
1113 }
Andreas Huberd0332ad2010-04-12 16:05:57 -07001114 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1115 // For legacy reasons we're simply going to ignore the absence
1116 // of an audio decoder for QCELP instead of aborting playback
1117 // altogether.
1118 return OK;
1119 }
Andreas Huberdc9927d2010-03-08 15:46:13 -08001120
Andreas Huber27366fc2009-11-20 09:32:46 -08001121 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1122}
1123
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001124void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1125 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001126
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001127 mVideoTrack = source;
1128}
1129
Andreas Huber4c19bf92010-09-08 14:32:20 -07001130status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001131 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001132 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -08001133 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -07001134 mVideoTrack,
Jamie Gennis58a36ad2010-10-07 14:08:38 -07001135 NULL, flags, mSurface);
Andreas Huber27366fc2009-11-20 09:32:46 -08001136
1137 if (mVideoSource != NULL) {
1138 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001139 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001140 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001141 if (mDurationUs < 0 || durationUs > mDurationUs) {
1142 mDurationUs = durationUs;
1143 }
1144 }
1145
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001146 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
1147 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -08001148
Andreas Huber1919e5a2010-05-20 10:37:06 -07001149 status_t err = mVideoSource->start();
1150
1151 if (err != OK) {
1152 mVideoSource.clear();
1153 return err;
1154 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001155 }
1156
1157 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1158}
1159
Andreas Huber4d450a82010-10-19 09:34:44 -07001160void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1161 if (!mSeeking) {
1162 return;
1163 }
1164
1165 if (mAudioPlayer != NULL) {
Jamie Gennis6913c612010-10-20 15:55:43 -07001166 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
Andreas Huber4d450a82010-10-19 09:34:44 -07001167
1168 // If we don't have a video time, seek audio to the originally
1169 // requested seek time instead.
1170
1171 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1172 mAudioPlayer->resume();
1173 mWatchForAudioSeekComplete = true;
1174 mWatchForAudioEOS = true;
1175 } else if (!mSeekNotificationSent) {
1176 // If we're playing video only, report seek complete now,
1177 // otherwise audio player will notify us later.
1178 notifyListener_l(MEDIA_SEEK_COMPLETE);
1179 }
1180
1181 mFlags |= FIRST_FRAME;
1182 mSeeking = false;
1183 mSeekNotificationSent = false;
Gloria Wang3f9a8192010-10-29 14:50:17 -07001184
1185 if (mDecryptHandle != NULL) {
1186 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1187 Playback::PAUSE, 0);
1188 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1189 Playback::START, videoTimeUs / 1000);
1190 }
Andreas Huber4d450a82010-10-19 09:34:44 -07001191}
1192
Andreas Huber6be780e2010-02-08 14:40:30 -08001193void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001194 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001195 if (!mVideoEventPending) {
1196 // The event has been cancelled in reset_l() but had already
1197 // been scheduled for execution at that time.
1198 return;
1199 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001200 mVideoEventPending = false;
1201
1202 if (mSeeking) {
1203 if (mLastVideoBuffer) {
1204 mLastVideoBuffer->release();
1205 mLastVideoBuffer = NULL;
1206 }
1207
1208 if (mVideoBuffer) {
1209 mVideoBuffer->release();
1210 mVideoBuffer = NULL;
1211 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001212
1213 if (mCachedSource != NULL && mAudioSource != NULL) {
1214 // We're going to seek the video source first, followed by
1215 // the audio source.
1216 // In order to avoid jumps in the DataSource offset caused by
1217 // the audio codec prefetching data from the old locations
1218 // while the video codec is already reading data from the new
1219 // locations, we'll "pause" the audio source, causing it to
1220 // stop reading input data until a subsequent seek.
1221
1222 if (mAudioPlayer != NULL) {
1223 mAudioPlayer->pause();
1224 }
1225 mAudioSource->pause();
1226 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001227 }
1228
1229 if (!mVideoBuffer) {
1230 MediaSource::ReadOptions options;
1231 if (mSeeking) {
1232 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1233
Andreas Huber6624c9f2010-07-20 15:04:28 -07001234 options.setSeekTo(
1235 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001236 }
1237 for (;;) {
1238 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001239 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001240
1241 if (err != OK) {
1242 CHECK_EQ(mVideoBuffer, NULL);
1243
1244 if (err == INFO_FORMAT_CHANGED) {
1245 LOGV("VideoSource signalled format change.");
1246
Andreas Hubere3c01832010-08-16 08:49:37 -07001247 notifyVideoSize_l();
1248
Andreas Huber7085b6842010-02-03 16:02:02 -08001249 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001250 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001251 initRenderer_l();
1252 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001253 continue;
1254 }
1255
Andreas Huber4d450a82010-10-19 09:34:44 -07001256 // So video playback is complete, but we may still have
1257 // a seek request pending that needs to be applied
1258 // to the audio track.
1259 if (mSeeking) {
1260 LOGV("video stream ended while seeking!");
1261 }
1262 finishSeekIfNecessary(-1);
1263
Andreas Huber971305d2010-07-07 13:35:27 -07001264 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001265 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001266 return;
1267 }
1268
Andreas Hubera67d5382009-12-10 15:32:12 -08001269 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001270 // Some decoders, notably the PV AVC software decoder
1271 // return spurious empty buffers that we just want to ignore.
1272
Andreas Hubera67d5382009-12-10 15:32:12 -08001273 mVideoBuffer->release();
1274 mVideoBuffer = NULL;
1275 continue;
1276 }
1277
Andreas Huber27366fc2009-11-20 09:32:46 -08001278 break;
1279 }
1280 }
1281
1282 int64_t timeUs;
1283 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1284
Andreas Huber252573c2010-03-26 10:17:17 -07001285 {
1286 Mutex::Autolock autoLock(mMiscStateLock);
1287 mVideoTimeUs = timeUs;
1288 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001289
Andreas Huber614d22c2010-10-29 15:47:52 -07001290 bool wasSeeking = mSeeking;
Andreas Huber4d450a82010-10-19 09:34:44 -07001291 finishSeekIfNecessary(timeUs);
Andreas Huber27366fc2009-11-20 09:32:46 -08001292
Andreas Huber971305d2010-07-07 13:35:27 -07001293 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1294
Andreas Huber27366fc2009-11-20 09:32:46 -08001295 if (mFlags & FIRST_FRAME) {
1296 mFlags &= ~FIRST_FRAME;
1297
Andreas Huber971305d2010-07-07 13:35:27 -07001298 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001299 }
1300
1301 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001302 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001303 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1304 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1305 }
1306
Andreas Huber971305d2010-07-07 13:35:27 -07001307 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001308
1309 int64_t latenessUs = nowUs - timeUs;
1310
Andreas Huber614d22c2010-10-29 15:47:52 -07001311 if (wasSeeking) {
1312 // Let's display the first frame after seeking right away.
1313 latenessUs = 0;
1314 }
1315
Andreas Huberf88f8442010-08-10 11:18:36 -07001316 if (mRTPSession != NULL) {
1317 // We'll completely ignore timestamps for gtalk videochat
1318 // and we'll play incoming video as fast as we get it.
1319 latenessUs = 0;
1320 }
1321
Andreas Huber24b0a952009-11-23 14:02:00 -08001322 if (latenessUs > 40000) {
1323 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001324 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001325
1326 mVideoBuffer->release();
1327 mVideoBuffer = NULL;
1328
1329 postVideoEvent_l();
1330 return;
1331 }
1332
1333 if (latenessUs < -10000) {
1334 // We're more than 10ms early.
1335
1336 postVideoEvent_l(10000);
1337 return;
1338 }
1339
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001340 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1341 mVideoRendererIsPreview = false;
1342
Andreas Huber7085b6842010-02-03 16:02:02 -08001343 initRenderer_l();
1344 }
1345
1346 if (mVideoRenderer != NULL) {
1347 mVideoRenderer->render(mVideoBuffer);
1348 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001349
1350 if (mLastVideoBuffer) {
1351 mLastVideoBuffer->release();
1352 mLastVideoBuffer = NULL;
1353 }
1354 mLastVideoBuffer = mVideoBuffer;
1355 mVideoBuffer = NULL;
1356
1357 postVideoEvent_l();
1358}
1359
1360void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1361 if (mVideoEventPending) {
1362 return;
1363 }
1364
1365 mVideoEventPending = true;
1366 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1367}
1368
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001369void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001370 if (mStreamDoneEventPending) {
1371 return;
1372 }
1373 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001374
1375 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001376 mQueue.postEvent(mStreamDoneEvent);
1377}
1378
Andreas Huberb9e63832010-01-26 16:20:10 -08001379void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001380 if (mBufferingEventPending) {
1381 return;
1382 }
1383 mBufferingEventPending = true;
1384 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1385}
1386
Andreas Huber70d10c02010-02-03 11:37:29 -08001387void AwesomePlayer::postCheckAudioStatusEvent_l() {
1388 if (mAudioStatusEventPending) {
1389 return;
1390 }
1391 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001392 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001393}
1394
1395void AwesomePlayer::onCheckAudioStatus() {
1396 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001397 if (!mAudioStatusEventPending) {
1398 // Event was dispatched and while we were blocking on the mutex,
1399 // has already been cancelled.
1400 return;
1401 }
1402
Andreas Huber70d10c02010-02-03 11:37:29 -08001403 mAudioStatusEventPending = false;
1404
1405 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1406 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001407
1408 if (!mSeekNotificationSent) {
1409 notifyListener_l(MEDIA_SEEK_COMPLETE);
1410 mSeekNotificationSent = true;
1411 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001412
1413 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001414 }
1415
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001416 status_t finalStatus;
1417 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001418 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001419 mFlags |= AUDIO_AT_EOS;
1420 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001421 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001422 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001423}
1424
Andreas Huber6be780e2010-02-08 14:40:30 -08001425status_t AwesomePlayer::prepare() {
1426 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001427 return prepare_l();
1428}
Andreas Huber6be780e2010-02-08 14:40:30 -08001429
Andreas Huberffdf4782010-02-09 14:05:43 -08001430status_t AwesomePlayer::prepare_l() {
1431 if (mFlags & PREPARED) {
1432 return OK;
1433 }
1434
1435 if (mFlags & PREPARING) {
1436 return UNKNOWN_ERROR;
1437 }
1438
1439 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001440 status_t err = prepareAsync_l();
1441
1442 if (err != OK) {
1443 return err;
1444 }
1445
Andreas Huberffdf4782010-02-09 14:05:43 -08001446 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001447 mPreparedCondition.wait(mLock);
1448 }
1449
Andreas Huberffdf4782010-02-09 14:05:43 -08001450 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001451}
1452
1453status_t AwesomePlayer::prepareAsync() {
1454 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001455
1456 if (mFlags & PREPARING) {
1457 return UNKNOWN_ERROR; // async prepare already pending
1458 }
1459
1460 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001461 return prepareAsync_l();
1462}
1463
1464status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001465 if (mFlags & PREPARING) {
1466 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001467 }
1468
Andreas Huber406a18b2010-02-18 16:45:13 -08001469 if (!mQueueStarted) {
1470 mQueue.start();
1471 mQueueStarted = true;
1472 }
1473
Andreas Huberffdf4782010-02-09 14:05:43 -08001474 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001475 mAsyncPrepareEvent = new AwesomeEvent(
1476 this, &AwesomePlayer::onPrepareAsyncEvent);
1477
1478 mQueue.postEvent(mAsyncPrepareEvent);
1479
1480 return OK;
1481}
1482
Andreas Huberffdf4782010-02-09 14:05:43 -08001483status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001484 sp<DataSource> dataSource;
1485
1486 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001487 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001488
1489 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001490 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001491 mLock.lock();
1492
1493 if (err != OK) {
1494 mConnectingDataSource.clear();
1495
1496 LOGI("mConnectingDataSource->connect() returned %d", err);
1497 return err;
1498 }
1499
Andreas Huber4d61f602010-06-10 11:17:50 -07001500#if 0
1501 mCachedSource = new NuCachedSource2(
1502 new ThrottledSource(
1503 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1504#else
1505 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1506#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001507 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001508
1509 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001510 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1511 String8 uri("http://");
1512 uri.append(mUri.string() + 11);
1513
Andreas Huber54d09722010-10-12 11:34:37 -07001514 sp<LiveSource> liveSource = new LiveSource(uri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001515
Andreas Huber54d09722010-10-12 11:34:37 -07001516 mCachedSource = new NuCachedSource2(liveSource);
Andreas Huber4d61f602010-06-10 11:17:50 -07001517 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001518
1519 sp<MediaExtractor> extractor =
1520 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001521
Andreas Huber54d09722010-10-12 11:34:37 -07001522 static_cast<MPEG2TSExtractor *>(extractor.get())
1523 ->setLiveSource(liveSource);
1524
Andreas Huber4d61f602010-06-10 11:17:50 -07001525 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001526 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001527 if (mLooper == NULL) {
1528 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001529 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001530 mLooper->start(
1531 false /* runOnCallingThread */,
1532 false /* canCallJava */,
1533 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001534 }
1535
Mike Dodd8741dfa2010-08-12 16:04:35 -07001536 const char *startOfCodecString = &mUri.string()[13];
1537 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1538 if (startOfSlash1 == NULL) {
1539 return BAD_VALUE;
1540 }
1541 const char *startOfWidthString = &startOfSlash1[1];
1542 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1543 if (startOfSlash2 == NULL) {
1544 return BAD_VALUE;
1545 }
1546 const char *startOfHeightString = &startOfSlash2[1];
1547
1548 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1549 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1550 String8 heightString(startOfHeightString);
1551
Andreas Huber57648e42010-08-04 10:14:30 -07001552#if 0
1553 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1554 mLooper->registerHandler(mRTPPusher);
1555
1556 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1557 mLooper->registerHandler(mRTCPPusher);
1558#endif
1559
1560 mRTPSession = new ARTPSession;
1561 mLooper->registerHandler(mRTPSession);
1562
1563#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001564 // My AMR SDP
1565 static const char *raw =
1566 "v=0\r\n"
1567 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1568 "s=QuickTime\r\n"
1569 "t=0 0\r\n"
1570 "a=range:npt=0-315\r\n"
1571 "a=isma-compliance:2,2.0,2\r\n"
1572 "m=audio 5434 RTP/AVP 97\r\n"
1573 "c=IN IP4 127.0.0.1\r\n"
1574 "b=AS:30\r\n"
1575 "a=rtpmap:97 AMR/8000/1\r\n"
1576 "a=fmtp:97 octet-align\r\n";
1577#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001578 String8 sdp;
1579 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001580 "v=0\r\n"
1581 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1582 "s=QuickTime\r\n"
1583 "t=0 0\r\n"
1584 "a=range:npt=0-315\r\n"
1585 "a=isma-compliance:2,2.0,2\r\n"
1586 "m=video 5434 RTP/AVP 97\r\n"
1587 "c=IN IP4 127.0.0.1\r\n"
1588 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001589 "a=rtpmap:97 %s/90000\r\n"
1590 "a=cliprect:0,0,%s,%s\r\n"
1591 "a=framesize:97 %s-%s\r\n",
1592
1593 codecString.string(),
1594 heightString.string(), widthString.string(),
1595 widthString.string(), heightString.string()
1596 );
1597 const char *raw = sdp.string();
1598
Andreas Huber57648e42010-08-04 10:14:30 -07001599#endif
1600
1601 sp<ASessionDescription> desc = new ASessionDescription;
1602 CHECK(desc->setTo(raw, strlen(raw)));
1603
1604 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1605
1606 if (mRTPPusher != NULL) {
1607 mRTPPusher->start();
1608 }
1609
1610 if (mRTCPPusher != NULL) {
1611 mRTCPPusher->start();
1612 }
1613
1614 CHECK_EQ(mRTPSession->countTracks(), 1u);
1615 sp<MediaSource> source = mRTPSession->trackAt(0);
1616
1617#if 0
1618 bool eos;
1619 while (((APacketSource *)source.get())
1620 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1621 usleep(100000ll);
1622 }
1623#endif
1624
1625 const char *mime;
1626 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1627
1628 if (!strncasecmp("video/", mime, 6)) {
1629 setVideoSource(source);
1630 } else {
1631 CHECK(!strncasecmp("audio/", mime, 6));
1632 setAudioSource(source);
1633 }
1634
1635 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1636
1637 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001638 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1639 if (mLooper == NULL) {
1640 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001641 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001642 mLooper->start();
1643 }
1644 mRTSPController = new ARTSPController(mLooper);
1645 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001646
Andreas Huber7a747b82010-06-07 15:19:40 -07001647 LOGI("ARTSPController::connect returned %d", err);
1648
1649 if (err != OK) {
1650 mRTSPController.clear();
1651 return err;
1652 }
1653
1654 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001655 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001656 } else {
1657 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1658 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001659
1660 if (dataSource == NULL) {
1661 return UNKNOWN_ERROR;
1662 }
1663
1664 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1665
1666 if (extractor == NULL) {
1667 return UNKNOWN_ERROR;
1668 }
1669
Gloria Wangd5770912010-06-22 13:55:38 -07001670 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangc2c22e72010-11-01 15:53:16 -07001671 if (mDecryptHandle != NULL) {
1672 if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
1673 if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) {
1674 LOGD("Setting mCachedSource to NULL for WVM\n");
1675 mCachedSource.clear();
1676 }
1677 } else {
1678 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
1679 }
Gloria Wangd5770912010-06-22 13:55:38 -07001680 }
1681
Andreas Huberffdf4782010-02-09 14:05:43 -08001682 return setDataSource_l(extractor);
1683}
1684
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001685void AwesomePlayer::abortPrepare(status_t err) {
1686 CHECK(err != OK);
1687
1688 if (mIsAsyncPrepare) {
1689 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1690 }
1691
1692 mPrepareResult = err;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001693 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001694 mAsyncPrepareEvent = NULL;
1695 mPreparedCondition.broadcast();
1696}
1697
Andreas Huberf71daba2010-03-24 09:24:40 -07001698// static
1699bool AwesomePlayer::ContinuePreparation(void *cookie) {
1700 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1701
1702 return (me->mFlags & PREPARE_CANCELLED) == 0;
1703}
1704
Andreas Huber6be780e2010-02-08 14:40:30 -08001705void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001706 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001707
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001708 if (mFlags & PREPARE_CANCELLED) {
1709 LOGI("prepare was cancelled before doing anything");
1710 abortPrepare(UNKNOWN_ERROR);
1711 return;
1712 }
1713
1714 if (mUri.size() > 0) {
1715 status_t err = finishSetDataSource_l();
1716
1717 if (err != OK) {
1718 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001719 return;
1720 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001721 }
1722
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001723 if (mVideoTrack != NULL && mVideoSource == NULL) {
1724 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001725
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001726 if (err != OK) {
1727 abortPrepare(err);
1728 return;
1729 }
1730 }
1731
1732 if (mAudioTrack != NULL && mAudioSource == NULL) {
1733 status_t err = initAudioDecoder();
1734
1735 if (err != OK) {
1736 abortPrepare(err);
1737 return;
1738 }
1739 }
1740
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001741 mFlags |= PREPARING_CONNECTED;
1742
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001743 if (mCachedSource != NULL || mRTSPController != NULL) {
1744 postBufferingEvent_l();
1745 } else {
1746 finishAsyncPrepare_l();
1747 }
1748}
1749
1750void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001751 if (mIsAsyncPrepare) {
Andreas Hubere3c01832010-08-16 08:49:37 -07001752 if (mVideoSource == NULL) {
Andreas Huberffdf4782010-02-09 14:05:43 -08001753 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1754 } else {
Andreas Hubere3c01832010-08-16 08:49:37 -07001755 notifyVideoSize_l();
Andreas Huberffdf4782010-02-09 14:05:43 -08001756 }
1757
1758 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001759 }
1760
Andreas Huberffdf4782010-02-09 14:05:43 -08001761 mPrepareResult = OK;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001762 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001763 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001764 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001765 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001766}
1767
Andreas Huberba7ec912010-02-12 10:42:02 -08001768status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001769 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001770 Mutex::Autolock autoLock(mLock);
1771
1772 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001773 if (mLastVideoBuffer == NULL) {
1774 //go into here if video is suspended again
1775 //after resuming without being played between
1776 //them
1777 SuspensionState *state = mSuspensionState;
1778 mSuspensionState = NULL;
1779 reset_l();
1780 mSuspensionState = state;
1781 return OK;
1782 }
1783
1784 delete mSuspensionState;
1785 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001786 }
1787
Andreas Huberedbb4d82010-03-12 08:59:22 -08001788 if (mFlags & PREPARING) {
1789 mFlags |= PREPARE_CANCELLED;
1790 if (mConnectingDataSource != NULL) {
1791 LOGI("interrupting the connection process");
1792 mConnectingDataSource->disconnect();
1793 }
1794 }
1795
Andreas Huberba7ec912010-02-12 10:42:02 -08001796 while (mFlags & PREPARING) {
1797 mPreparedCondition.wait(mLock);
1798 }
1799
1800 SuspensionState *state = new SuspensionState;
1801 state->mUri = mUri;
1802 state->mUriHeaders = mUriHeaders;
1803 state->mFileSource = mFileSource;
1804
Andreas Huber9fee0b22010-09-03 14:09:21 -07001805 state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001806 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001807
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001808 if (mLastVideoBuffer) {
1809 size_t size = mLastVideoBuffer->range_length();
Andreas Huber1e194162010-10-06 16:43:57 -07001810
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001811 if (size) {
Andreas Huber1e194162010-10-06 16:43:57 -07001812 int32_t unreadable;
1813 if (!mLastVideoBuffer->meta_data()->findInt32(
1814 kKeyIsUnreadable, &unreadable)
1815 || unreadable == 0) {
1816 state->mLastVideoFrameSize = size;
1817 state->mLastVideoFrame = malloc(size);
1818 memcpy(state->mLastVideoFrame,
1819 (const uint8_t *)mLastVideoBuffer->data()
1820 + mLastVideoBuffer->range_offset(),
1821 size);
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001822
Andreas Huber1e194162010-10-06 16:43:57 -07001823 state->mVideoWidth = mVideoWidth;
1824 state->mVideoHeight = mVideoHeight;
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001825
Andreas Huber1e194162010-10-06 16:43:57 -07001826 sp<MetaData> meta = mVideoSource->getFormat();
1827 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1828 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1829 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1830 } else {
1831 LOGV("Unable to save last video frame, we have no access to "
1832 "the decoded video data.");
1833 }
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001834 }
1835 }
1836
Andreas Huberba7ec912010-02-12 10:42:02 -08001837 reset_l();
1838
1839 mSuspensionState = state;
1840
1841 return OK;
1842}
1843
1844status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001845 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001846 Mutex::Autolock autoLock(mLock);
1847
1848 if (mSuspensionState == NULL) {
1849 return INVALID_OPERATION;
1850 }
1851
1852 SuspensionState *state = mSuspensionState;
1853 mSuspensionState = NULL;
1854
1855 status_t err;
1856 if (state->mFileSource != NULL) {
1857 err = setDataSource_l(state->mFileSource);
1858
1859 if (err == OK) {
1860 mFileSource = state->mFileSource;
1861 }
1862 } else {
1863 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1864 }
1865
1866 if (err != OK) {
1867 delete state;
1868 state = NULL;
1869
1870 return err;
1871 }
1872
1873 seekTo_l(state->mPositionUs);
1874
Andreas Huber9fee0b22010-09-03 14:09:21 -07001875 mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001876
Andreas Hubere3c01832010-08-16 08:49:37 -07001877 if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001878 mVideoRenderer =
1879 new AwesomeLocalRenderer(
1880 true, // previewOnly
1881 "",
1882 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1883 mISurface,
Andreas Hubere3c01832010-08-16 08:49:37 -07001884 mSurface,
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001885 state->mVideoWidth,
1886 state->mVideoHeight,
1887 state->mDecodedWidth,
1888 state->mDecodedHeight);
1889
1890 mVideoRendererIsPreview = true;
1891
1892 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1893 state->mLastVideoFrame, state->mLastVideoFrameSize);
1894 }
1895
Andreas Huberba7ec912010-02-12 10:42:02 -08001896 if (state->mFlags & PLAYING) {
1897 play_l();
1898 }
1899
Gloria Wangb19da8e2010-04-12 17:13:06 -07001900 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001901 state = NULL;
1902
1903 return OK;
1904}
1905
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001906uint32_t AwesomePlayer::flags() const {
1907 return mExtractorFlags;
1908}
1909
Andreas Huber2b359ed2010-09-28 11:56:39 -07001910void AwesomePlayer::postAudioEOS() {
1911 postCheckAudioStatusEvent_l();
1912}
1913
1914void AwesomePlayer::postAudioSeekComplete() {
1915 postCheckAudioStatusEvent_l();
1916}
1917
Andreas Huber27366fc2009-11-20 09:32:46 -08001918} // namespace android