blob: 2743a3a8028d6f451e4e3fb1a5c96ed7187047e7 [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 Huber1314e732009-12-14 14:18:22 -080025#include "include/SoftwareRenderer.h"
Andreas Huber4d61f602010-06-10 11:17:50 -070026#include "include/NuCachedSource2.h"
27#include "include/ThrottledSource.h"
Andreas Huber54d09722010-10-12 11:34:37 -070028#include "include/MPEG2TSExtractor.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080029
Andreas Huber57648e42010-08-04 10:14:30 -070030#include "ARTPSession.h"
31#include "APacketSource.h"
32#include "ASessionDescription.h"
33#include "UDPPusher.h"
34
Andreas Hubera67d5382009-12-10 15:32:12 -080035#include <binder/IPCThreadState.h>
Andreas Huber52b52cd2010-11-23 11:41:34 -080036#include <binder/MemoryDealer.h>
37#include <media/IStreamSource.h>
38#include <media/stagefright/foundation/hexdump.h>
39#include <media/stagefright/foundation/ADebug.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080040#include <media/stagefright/AudioPlayer.h>
41#include <media/stagefright/DataSource.h>
42#include <media/stagefright/FileSource.h>
43#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080044#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080045#include <media/stagefright/MediaExtractor.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080046#include <media/stagefright/MediaSource.h>
47#include <media/stagefright/MetaData.h>
48#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080049
Andreas Hubere3c01832010-08-16 08:49:37 -070050#include <surfaceflinger/Surface.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080051
Andreas Huber7a747b82010-06-07 15:19:40 -070052#include <media/stagefright/foundation/ALooper.h>
Andreas Huberb5590842010-12-03 16:12:25 -080053#include "include/LiveSession.h"
Andreas Huber202348e2010-06-07 14:35:29 -070054
Andreas Huber6a1f5f92010-11-15 09:03:03 -080055#define USE_SURFACE_ALLOC 1
56
Andreas Huber27366fc2009-11-20 09:32:46 -080057namespace android {
58
Andreas Huber87ab9cd2010-09-03 13:20:33 -070059static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
60static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
61
Andreas Huber27366fc2009-11-20 09:32:46 -080062struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080063 AwesomeEvent(
64 AwesomePlayer *player,
65 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080066 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080067 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080068 }
69
70protected:
71 virtual ~AwesomeEvent() {}
72
73 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080074 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080075 }
76
77private:
78 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080079 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080080
81 AwesomeEvent(const AwesomeEvent &);
82 AwesomeEvent &operator=(const AwesomeEvent &);
83};
84
Andreas Huber1314e732009-12-14 14:18:22 -080085struct AwesomeLocalRenderer : public AwesomeRenderer {
86 AwesomeLocalRenderer(
Andreas Huber1bb0ffd2010-11-22 13:06:35 -080087 const sp<Surface> &surface, const sp<MetaData> &meta)
88 : mTarget(new SoftwareRenderer(surface, meta)) {
Andreas Huber1314e732009-12-14 14:18:22 -080089 }
90
91 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -080092 render((const uint8_t *)buffer->data() + buffer->range_offset(),
93 buffer->range_length());
94 }
95
96 void render(const void *data, size_t size) {
97 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -080098 }
99
100protected:
101 virtual ~AwesomeLocalRenderer() {
102 delete mTarget;
103 mTarget = NULL;
104 }
105
106private:
Andreas Huberc23dabf2010-11-16 13:05:53 -0800107 SoftwareRenderer *mTarget;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800108
Andreas Huber1314e732009-12-14 14:18:22 -0800109 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
110 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
111};
112
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700113struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
Andreas Huber940c8662010-11-16 15:26:30 -0800114 AwesomeNativeWindowRenderer(
115 const sp<ANativeWindow> &nativeWindow,
116 int32_t rotationDegrees)
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700117 : mNativeWindow(nativeWindow) {
Andreas Huber940c8662010-11-16 15:26:30 -0800118 applyRotation(rotationDegrees);
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700119 }
120
121 virtual void render(MediaBuffer *buffer) {
122 status_t err = mNativeWindow->queueBuffer(
123 mNativeWindow.get(), buffer->graphicBuffer().get());
124 if (err != 0) {
125 LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
126 -err);
127 return;
128 }
129
130 sp<MetaData> metaData = buffer->meta_data();
131 metaData->setInt32(kKeyRendered, 1);
132 }
133
134protected:
135 virtual ~AwesomeNativeWindowRenderer() {}
136
137private:
138 sp<ANativeWindow> mNativeWindow;
139
Andreas Huber940c8662010-11-16 15:26:30 -0800140 void applyRotation(int32_t rotationDegrees) {
141 uint32_t transform;
142 switch (rotationDegrees) {
143 case 0: transform = 0; break;
144 case 90: transform = HAL_TRANSFORM_ROT_90; break;
145 case 180: transform = HAL_TRANSFORM_ROT_180; break;
146 case 270: transform = HAL_TRANSFORM_ROT_270; break;
147 default: transform = 0; break;
148 }
149
150 if (transform) {
151 CHECK_EQ(0, native_window_set_buffers_transform(
152 mNativeWindow.get(), transform));
153 }
154 }
155
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700156 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
157 AwesomeNativeWindowRenderer &operator=(
158 const AwesomeNativeWindowRenderer &);
159};
160
Andreas Huber52b52cd2010-11-23 11:41:34 -0800161////////////////////////////////////////////////////////////////////////////////
162
163struct QueueDataSource;
164
165struct QueueListener : public BnStreamListener {
166 QueueListener(QueueDataSource *owner)
167 : mOwner(owner) {
168 }
169
170 void clearOwner();
171
172 virtual void queueBuffer(size_t index, size_t size);
173 virtual void queueCommand(Command cmd);
174
175private:
176 Mutex mLock;
177
178 QueueDataSource *mOwner;
179
180 DISALLOW_EVIL_CONSTRUCTORS(QueueListener);
181};
182
183struct QueueDataSource : public DataSource {
184 QueueDataSource(const sp<IStreamSource> &source);
185
186 virtual status_t initCheck() const;
187
188 virtual ssize_t readAt(off64_t offset, void *data, size_t size);
189
190 virtual void queueBuffer(size_t index, size_t size);
191 virtual void queueCommand(IStreamListener::Command cmd);
192
193protected:
194 virtual ~QueueDataSource();
195
196private:
197 enum {
198 kNumBuffers = 16
199 };
200
201 struct BufferInfo {
202 size_t mIndex;
203 size_t mOffset;
204 size_t mSize;
205 };
206
207 Mutex mLock;
208 Condition mCondition;
209
210 sp<IStreamSource> mSource;
211 sp<QueueListener> mListener;
212 sp<MemoryDealer> mDealer;
213 Vector<sp<IMemory> > mBuffers;
214
215 List<BufferInfo> mFilledBuffers;
216
217 off64_t mPosition;
218 bool mEOS;
219
220 DISALLOW_EVIL_CONSTRUCTORS(QueueDataSource);
221};
222
223QueueDataSource::QueueDataSource(const sp<IStreamSource> &source)
224 : mSource(source),
225 mPosition(0),
226 mEOS(false) {
227 mListener = new QueueListener(this);
228 mSource->setListener(mListener);
229
230 static const size_t kBufferSize = 8192;
231
232 mDealer = new MemoryDealer(kNumBuffers * kBufferSize);
233 for (size_t i = 0; i < kNumBuffers; ++i) {
234 sp<IMemory> mem = mDealer->allocate(kBufferSize);
235 CHECK(mem != NULL);
236
237 mBuffers.push(mem);
238 }
239 mSource->setBuffers(mBuffers);
240
241 for (size_t i = 0; i < kNumBuffers; ++i) {
242 mSource->onBufferAvailable(i);
243 }
244}
245
246QueueDataSource::~QueueDataSource() {
247 Mutex::Autolock autoLock(mLock);
248
249 while (mFilledBuffers.size() < kNumBuffers && !mEOS) {
250 mCondition.wait(mLock);
251 }
252
253 mListener->clearOwner();
254}
255
256status_t QueueDataSource::initCheck() const {
257 return OK;
258}
259
260ssize_t QueueDataSource::readAt(off64_t offset, void *data, size_t size) {
261 if (offset != mPosition) {
262 return -EPIPE;
263 }
264
265 Mutex::Autolock autoLock(mLock);
266
267 size_t sizeDone = 0;
268
269 while (sizeDone < size) {
270 while (mFilledBuffers.empty() && !mEOS) {
271 mCondition.wait(mLock);
272 }
273
274 if (mFilledBuffers.empty()) {
275 if (sizeDone > 0) {
276 mPosition += sizeDone;
277 return sizeDone;
278 }
279 return ERROR_END_OF_STREAM;
280 }
281
282 BufferInfo &info = *mFilledBuffers.begin();
283
284 size_t copy = size - sizeDone;
285 if (copy > info.mSize) {
286 copy = info.mSize;
287 }
288
289 memcpy((uint8_t *)data + sizeDone,
290 (const uint8_t *)mBuffers.itemAt(info.mIndex)->pointer()
291 + info.mOffset,
292 copy);
293
294 info.mSize -= copy;
295 info.mOffset += copy;
296 sizeDone += copy;
297
298 if (info.mSize == 0) {
299 mSource->onBufferAvailable(info.mIndex);
300 mFilledBuffers.erase(mFilledBuffers.begin());
301 }
302 }
303
304 mPosition += sizeDone;
305
306 return sizeDone;
307}
308
309void QueueDataSource::queueBuffer(size_t index, size_t size) {
310 Mutex::Autolock autoLock(mLock);
311
312 CHECK_LT(index, mBuffers.size());
313 CHECK_LE(size, mBuffers.itemAt(index)->size());
314
315 BufferInfo info;
316 info.mIndex = index;
317 info.mSize = size;
318 info.mOffset = 0;
319
320 mFilledBuffers.push_back(info);
321 mCondition.signal();
322}
323
324void QueueDataSource::queueCommand(IStreamListener::Command cmd) {
325 Mutex::Autolock autoLock(mLock);
326
327 if (cmd == IStreamListener::EOS) {
328 mEOS = true;
329 mCondition.signal();
330 }
331}
332
333void QueueListener::clearOwner() {
334 Mutex::Autolock autoLock(mLock);
335 mOwner = NULL;
336}
337
338void QueueListener::queueBuffer(size_t index, size_t size) {
339 Mutex::Autolock autoLock(mLock);
340 if (mOwner == NULL) {
341 return;
342 }
343 mOwner->queueBuffer(index, size);
344}
345
346void QueueListener::queueCommand(Command cmd) {
347 Mutex::Autolock autoLock(mLock);
348 if (mOwner == NULL) {
349 return;
350 }
351 mOwner->queueCommand(cmd);
352}
353
354////////////////////////////////////////////////////////////////////////////////
355
Andreas Huber27366fc2009-11-20 09:32:46 -0800356AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800357 : mQueueStarted(false),
358 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800359 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800360 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800361 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700362 mExtractorFlags(0),
Andreas Huberba7ec912010-02-12 10:42:02 -0800363 mVideoBuffer(NULL),
Gloria Wangd5770912010-06-22 13:55:38 -0700364 mDecryptHandle(NULL) {
Andreas Huber52b52cd2010-11-23 11:41:34 -0800365 CHECK_EQ(mClient.connect(), (status_t)OK);
Andreas Huber27366fc2009-11-20 09:32:46 -0800366
367 DataSource::RegisterDefaultSniffers();
368
Andreas Huber6be780e2010-02-08 14:40:30 -0800369 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800370 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800371 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800372 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800373 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800374 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800375
376 mCheckAudioStatusEvent = new AwesomeEvent(
377 this, &AwesomePlayer::onCheckAudioStatus);
378
Andreas Huber70d10c02010-02-03 11:37:29 -0800379 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800380
Andreas Huber27366fc2009-11-20 09:32:46 -0800381 reset();
382}
383
384AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800385 if (mQueueStarted) {
386 mQueue.stop();
387 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800388
389 reset();
390
391 mClient.disconnect();
392}
393
Andreas Huberb9e63832010-01-26 16:20:10 -0800394void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800395 mQueue.cancelEvent(mVideoEvent->eventID());
396 mVideoEventPending = false;
397 mQueue.cancelEvent(mStreamDoneEvent->eventID());
398 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800399 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
400 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800401
402 if (!keepBufferingGoing) {
403 mQueue.cancelEvent(mBufferingEvent->eventID());
404 mBufferingEventPending = false;
405 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800406}
407
Andreas Hubera3f43842010-01-21 10:28:45 -0800408void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800409 Mutex::Autolock autoLock(mLock);
410 mListener = listener;
411}
412
Andreas Huber433c9ac2010-01-27 16:49:05 -0800413status_t AwesomePlayer::setDataSource(
414 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800415 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800416 return setDataSource_l(uri, headers);
417}
Andreas Huber27366fc2009-11-20 09:32:46 -0800418
Andreas Huberba7ec912010-02-12 10:42:02 -0800419status_t AwesomePlayer::setDataSource_l(
420 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800421 reset_l();
422
Andreas Huberffdf4782010-02-09 14:05:43 -0800423 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800424
Andreas Huber6a1f5f92010-11-15 09:03:03 -0800425 if (!strncmp("http://", uri, 7)) {
426 // Hack to support http live.
427
428 size_t len = strlen(uri);
Andreas Huberb5c6afc2010-12-02 13:27:47 -0800429 if (!strcasecmp(&uri[len - 5], ".m3u8")
430 || strstr(&uri[7], "m3u8") != NULL) {
Andreas Huber6a1f5f92010-11-15 09:03:03 -0800431 mUri = "httplive://";
432 mUri.append(&uri[7]);
433 }
434 }
435
Andreas Huberffdf4782010-02-09 14:05:43 -0800436 if (headers) {
437 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800438 }
439
Andreas Huberffdf4782010-02-09 14:05:43 -0800440 // The actual work will be done during preparation in the call to
441 // ::finishSetDataSource_l to avoid blocking the calling thread in
442 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800443
Andreas Huberffdf4782010-02-09 14:05:43 -0800444 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800445}
446
447status_t AwesomePlayer::setDataSource(
448 int fd, int64_t offset, int64_t length) {
449 Mutex::Autolock autoLock(mLock);
450
451 reset_l();
452
Andreas Huberba7ec912010-02-12 10:42:02 -0800453 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800454
Andreas Huberba7ec912010-02-12 10:42:02 -0800455 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800456
457 if (err != OK) {
458 return err;
459 }
460
Andreas Huberba7ec912010-02-12 10:42:02 -0800461 mFileSource = dataSource;
462
463 return setDataSource_l(dataSource);
464}
465
Andreas Huber52b52cd2010-11-23 11:41:34 -0800466status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) {
467 Mutex::Autolock autoLock(mLock);
468
469 reset_l();
470
471 sp<DataSource> dataSource = new QueueDataSource(source);
472
473#if 0
474 sp<MediaExtractor> extractor =
475 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
476
477 return setDataSource_l(extractor);
478#else
479 sp<NuCachedSource2> cached = new NuCachedSource2(dataSource);
480 dataSource = cached;
481
482 return setDataSource_l(dataSource);
483#endif
484}
485
Andreas Huberba7ec912010-02-12 10:42:02 -0800486status_t AwesomePlayer::setDataSource_l(
487 const sp<DataSource> &dataSource) {
488 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800489
490 if (extractor == NULL) {
491 return UNKNOWN_ERROR;
492 }
493
Gloria Wangd5770912010-06-22 13:55:38 -0700494 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangeab18ea2010-10-29 10:09:47 -0700495 if (mDecryptHandle != NULL
496 && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
497 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
Gloria Wangd5770912010-06-22 13:55:38 -0700498 }
499
Andreas Huber27366fc2009-11-20 09:32:46 -0800500 return setDataSource_l(extractor);
501}
502
503status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700504 // Attempt to approximate overall stream bitrate by summing all
505 // tracks' individual bitrates, if not all of them advertise bitrate,
506 // we have to fail.
507
508 int64_t totalBitRate = 0;
509
510 for (size_t i = 0; i < extractor->countTracks(); ++i) {
511 sp<MetaData> meta = extractor->getTrackMetaData(i);
512
513 int32_t bitrate;
514 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
515 totalBitRate = -1;
516 break;
517 }
518
519 totalBitRate += bitrate;
520 }
521
522 mBitrate = totalBitRate;
523
524 LOGV("mBitrate = %lld bits/sec", mBitrate);
525
Andreas Huber27366fc2009-11-20 09:32:46 -0800526 bool haveAudio = false;
527 bool haveVideo = false;
528 for (size_t i = 0; i < extractor->countTracks(); ++i) {
529 sp<MetaData> meta = extractor->getTrackMetaData(i);
530
531 const char *mime;
532 CHECK(meta->findCString(kKeyMIMEType, &mime));
533
534 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800535 setVideoSource(extractor->getTrack(i));
536 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800537 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800538 setAudioSource(extractor->getTrack(i));
539 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700540
Andreas Huber1913c1a2010-10-04 11:09:31 -0700541 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
542 // Only do this for vorbis audio, none of the other audio
543 // formats even support this ringtone specific hack and
544 // retrieving the metadata on some extractors may turn out
545 // to be very expensive.
546 sp<MetaData> fileMeta = extractor->getMetaData();
547 int32_t loop;
548 if (fileMeta != NULL
549 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
550 mFlags |= AUTO_LOOPING;
551 }
Andreas Huber9fee0b22010-09-03 14:09:21 -0700552 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800553 }
554
555 if (haveAudio && haveVideo) {
556 break;
557 }
558 }
559
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700560 if (!haveAudio && !haveVideo) {
561 return UNKNOWN_ERROR;
562 }
563
564 mExtractorFlags = extractor->flags();
565
566 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800567}
568
569void AwesomePlayer::reset() {
570 Mutex::Autolock autoLock(mLock);
571 reset_l();
572}
573
574void AwesomePlayer::reset_l() {
Gloria Wangd5770912010-06-22 13:55:38 -0700575 if (mDecryptHandle != NULL) {
576 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
577 Playback::STOP, 0);
Gloria Wangc2c22e72010-11-01 15:53:16 -0700578 mDrmManagerClient->closeDecryptSession(mDecryptHandle);
Gloria Wangd5770912010-06-22 13:55:38 -0700579 mDecryptHandle = NULL;
580 mDrmManagerClient = NULL;
581 }
582
Andreas Huberedbb4d82010-03-12 08:59:22 -0800583 if (mFlags & PREPARING) {
584 mFlags |= PREPARE_CANCELLED;
585 if (mConnectingDataSource != NULL) {
586 LOGI("interrupting the connection process");
587 mConnectingDataSource->disconnect();
588 }
Andreas Hubereaf2c5a2010-10-19 12:18:51 -0700589
590 if (mFlags & PREPARING_CONNECTED) {
591 // We are basically done preparing, we're just buffering
592 // enough data to start playback, we can safely interrupt that.
593 finishAsyncPrepare_l();
594 }
Andreas Huberedbb4d82010-03-12 08:59:22 -0800595 }
596
Andreas Huberffdf4782010-02-09 14:05:43 -0800597 while (mFlags & PREPARING) {
598 mPreparedCondition.wait(mLock);
599 }
600
Andreas Huber27366fc2009-11-20 09:32:46 -0800601 cancelPlayerEvents();
602
Andreas Huber4d61f602010-06-10 11:17:50 -0700603 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800604 mAudioTrack.clear();
605 mVideoTrack.clear();
606
Andreas Huberba7ec912010-02-12 10:42:02 -0800607 // Shutdown audio first, so that the respone to the reset request
608 // appears to happen instantaneously as far as the user is concerned
609 // If we did this later, audio would continue playing while we
610 // shutdown the video-related resources and the player appear to
611 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800612 if (mAudioPlayer == NULL && mAudioSource != NULL) {
613 // If we had an audio player, it would have effectively
614 // taken possession of the audio source and stopped it when
615 // _it_ is stopped. Otherwise this is still our responsibility.
616 mAudioSource->stop();
617 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800618 mAudioSource.clear();
619
Andreas Huberba7ec912010-02-12 10:42:02 -0800620 mTimeSource = NULL;
621
622 delete mAudioPlayer;
623 mAudioPlayer = NULL;
624
Andreas Huber3522b5a52010-01-22 14:36:53 -0800625 mVideoRenderer.clear();
626
Andreas Huber27366fc2009-11-20 09:32:46 -0800627 if (mVideoBuffer) {
628 mVideoBuffer->release();
629 mVideoBuffer = NULL;
630 }
631
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700632 if (mRTSPController != NULL) {
633 mRTSPController->disconnect();
634 mRTSPController.clear();
635 }
636
Andreas Huberb5590842010-12-03 16:12:25 -0800637 if (mLiveSession != NULL) {
638 mLiveSession->disconnect();
639 mLiveSession.clear();
640 }
641
Andreas Huber57648e42010-08-04 10:14:30 -0700642 mRTPPusher.clear();
643 mRTCPPusher.clear();
644 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700645
Andreas Huber27366fc2009-11-20 09:32:46 -0800646 if (mVideoSource != NULL) {
647 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800648
649 // The following hack is necessary to ensure that the OMX
650 // component is completely released by the time we may try
651 // to instantiate it again.
652 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800653 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800654 while (tmp.promote() != NULL) {
655 usleep(1000);
656 }
657 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800658 }
659
Andreas Huber27366fc2009-11-20 09:32:46 -0800660 mDurationUs = -1;
661 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700662 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800663 mTimeSourceDeltaUs = 0;
664 mVideoTimeUs = 0;
665
666 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700667 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800668 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800669
Andreas Huberffdf4782010-02-09 14:05:43 -0800670 mUri.setTo("");
671 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800672
673 mFileSource.clear();
674
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700675 mBitrate = -1;
Andreas Huber27366fc2009-11-20 09:32:46 -0800676}
677
Andreas Huber6be780e2010-02-08 14:40:30 -0800678void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800679 if (mListener != NULL) {
680 sp<MediaPlayerBase> listener = mListener.promote();
681
682 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800683 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800684 }
685 }
686}
687
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700688bool AwesomePlayer::getBitrate(int64_t *bitrate) {
James Dongb1262a82010-11-16 14:04:54 -0800689 off64_t size;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700690 if (mDurationUs >= 0 && mCachedSource != NULL
691 && mCachedSource->getSize(&size) == OK) {
692 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
693 return true;
694 }
695
696 if (mBitrate >= 0) {
697 *bitrate = mBitrate;
698 return true;
699 }
700
701 *bitrate = 0;
702
703 return false;
704}
705
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700706// Returns true iff cached duration is available/applicable.
707bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700708 int64_t bitrate;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700709
710 if (mRTSPController != NULL) {
711 *durationUs = mRTSPController->getQueueDurationUs(eos);
712 return true;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700713 } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700714 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
715 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
716 return true;
717 }
718
719 return false;
720}
721
Andreas Huber10b920c2010-11-11 15:37:17 -0800722void AwesomePlayer::ensureCacheIsFetching_l() {
723 if (mCachedSource != NULL) {
724 mCachedSource->resumeFetchingIfNecessary();
725 }
726}
727
Andreas Huberb9e63832010-01-26 16:20:10 -0800728void AwesomePlayer::onBufferingUpdate() {
729 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800730 if (!mBufferingEventPending) {
731 return;
732 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800733 mBufferingEventPending = false;
734
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700735 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700736 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700737 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700738
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700739 if (eos) {
740 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700741 if (mFlags & PREPARING) {
742 LOGV("cache has reached EOS, prepare is done.");
743 finishAsyncPrepare_l();
744 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700745 } else {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700746 int64_t bitrate;
747 if (getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700748 size_t cachedSize = mCachedSource->cachedSize();
749 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
750
751 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
752 if (percentage > 100) {
753 percentage = 100;
754 }
755
756 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
757 } else {
758 // We don't know the bitrate of the stream, use absolute size
759 // limits to maintain the cache.
760
Andreas Huber54d09722010-10-12 11:34:37 -0700761 const size_t kLowWaterMarkBytes = 40000;
762 const size_t kHighWaterMarkBytes = 200000;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700763
764 if ((mFlags & PLAYING) && !eos
765 && (cachedDataRemaining < kLowWaterMarkBytes)) {
766 LOGI("cache is running low (< %d) , pausing.",
767 kLowWaterMarkBytes);
768 mFlags |= CACHE_UNDERRUN;
769 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800770 ensureCacheIsFetching_l();
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700771 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
772 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
773 if (mFlags & CACHE_UNDERRUN) {
774 LOGI("cache has filled up (> %d), resuming.",
775 kHighWaterMarkBytes);
776 mFlags &= ~CACHE_UNDERRUN;
777 play_l();
778 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
779 } else if (mFlags & PREPARING) {
780 LOGV("cache has filled up (> %d), prepare is done",
781 kHighWaterMarkBytes);
782 finishAsyncPrepare_l();
783 }
784 }
785 }
786 }
787 }
788
789 int64_t cachedDurationUs;
790 bool eos;
791 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber10b920c2010-11-11 15:37:17 -0800792 LOGV("cachedDurationUs = %.2f secs, eos=%d",
793 cachedDurationUs / 1E6, eos);
794
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700795 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700796 && (cachedDurationUs < kLowWaterMarkUs)) {
797 LOGI("cache is running low (%.2f secs) , pausing.",
798 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700799 mFlags |= CACHE_UNDERRUN;
800 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800801 ensureCacheIsFetching_l();
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700802 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700803 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
804 if (mFlags & CACHE_UNDERRUN) {
805 LOGI("cache has filled up (%.2f secs), resuming.",
806 cachedDurationUs / 1E6);
807 mFlags &= ~CACHE_UNDERRUN;
808 play_l();
809 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
810 } else if (mFlags & PREPARING) {
811 LOGV("cache has filled up (%.2f secs), prepare is done",
812 cachedDurationUs / 1E6);
813 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700814 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700815 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800816 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700817
Andreas Huber4d61f602010-06-10 11:17:50 -0700818 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800819}
820
Andreas Huber4c19bf92010-09-08 14:32:20 -0700821void AwesomePlayer::partial_reset_l() {
822 // Only reset the video renderer and shut down the video decoder.
823 // Then instantiate a new video decoder and resume video playback.
824
825 mVideoRenderer.clear();
826
Andreas Huber4c19bf92010-09-08 14:32:20 -0700827 if (mVideoBuffer) {
828 mVideoBuffer->release();
829 mVideoBuffer = NULL;
830 }
831
832 {
833 mVideoSource->stop();
834
835 // The following hack is necessary to ensure that the OMX
836 // component is completely released by the time we may try
837 // to instantiate it again.
838 wp<MediaSource> tmp = mVideoSource;
839 mVideoSource.clear();
840 while (tmp.promote() != NULL) {
841 usleep(1000);
842 }
843 IPCThreadState::self()->flushCommands();
844 }
845
Andreas Huber52b52cd2010-11-23 11:41:34 -0800846 CHECK_EQ((status_t)OK,
847 initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
Andreas Huber4c19bf92010-09-08 14:32:20 -0700848}
849
Andreas Huber27366fc2009-11-20 09:32:46 -0800850void AwesomePlayer::onStreamDone() {
851 // Posted whenever any stream finishes playing.
852
853 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800854 if (!mStreamDoneEventPending) {
855 return;
856 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800857 mStreamDoneEventPending = false;
858
Andreas Huber4c19bf92010-09-08 14:32:20 -0700859 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
860 // This special status is returned because an http live stream's
861 // video stream switched to a different bandwidth at this point
862 // and future data may have been encoded using different parameters.
863 // This requires us to shutdown the video decoder and reinstantiate
864 // a fresh one.
865
866 LOGV("INFO_DISCONTINUITY");
867
868 CHECK(mVideoSource != NULL);
869
870 partial_reset_l();
871 postVideoEvent_l();
872 return;
873 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700874 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
875
876 notifyListener_l(
877 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
878
Andreas Huberc743f452010-10-05 10:25:34 -0700879 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700880
881 mFlags |= AT_EOS;
882 return;
883 }
884
885 const bool allDone =
886 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
887 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
888
889 if (!allDone) {
890 return;
891 }
892
Andreas Huber9fee0b22010-09-03 14:09:21 -0700893 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800894 seekTo_l(0);
895
Andreas Huber7085b6842010-02-03 16:02:02 -0800896 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800897 postVideoEvent_l();
898 }
899 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700900 LOGV("MEDIA_PLAYBACK_COMPLETE");
901 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800902
Andreas Huberc743f452010-10-05 10:25:34 -0700903 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800904
905 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800906 }
907}
908
909status_t AwesomePlayer::play() {
910 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700911
912 mFlags &= ~CACHE_UNDERRUN;
913
Andreas Huberba7ec912010-02-12 10:42:02 -0800914 return play_l();
915}
Andreas Huber27366fc2009-11-20 09:32:46 -0800916
Andreas Huberba7ec912010-02-12 10:42:02 -0800917status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800918 if (mFlags & PLAYING) {
919 return OK;
920 }
921
Andreas Huberffdf4782010-02-09 14:05:43 -0800922 if (!(mFlags & PREPARED)) {
923 status_t err = prepare_l();
924
925 if (err != OK) {
926 return err;
927 }
928 }
929
Andreas Huber27366fc2009-11-20 09:32:46 -0800930 mFlags |= PLAYING;
931 mFlags |= FIRST_FRAME;
932
Andreas Huberc1d5c922009-12-10 15:49:04 -0800933 bool deferredAudioSeek = false;
934
Gloria Wang95dbffb2010-11-04 17:38:39 -0700935 if (mDecryptHandle != NULL) {
936 int64_t position;
937 getPosition(&position);
938 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
939 Playback::START, position / 1000);
940 }
941
Andreas Huber27366fc2009-11-20 09:32:46 -0800942 if (mAudioSource != NULL) {
943 if (mAudioPlayer == NULL) {
944 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700945 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800946 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800947
948 // We've already started the MediaSource in order to enable
949 // the prefetcher to read its data.
950 status_t err = mAudioPlayer->start(
951 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800952
953 if (err != OK) {
954 delete mAudioPlayer;
955 mAudioPlayer = NULL;
956
957 mFlags &= ~(PLAYING | FIRST_FRAME);
958
Gloria Wang95dbffb2010-11-04 17:38:39 -0700959 if (mDecryptHandle != NULL) {
960 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
961 Playback::STOP, 0);
962 }
963
Andreas Huber62eac002010-01-29 13:24:58 -0800964 return err;
965 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800966
Andreas Huber27366fc2009-11-20 09:32:46 -0800967 mTimeSource = mAudioPlayer;
968
Andreas Huberc1d5c922009-12-10 15:49:04 -0800969 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800970
971 mWatchForAudioSeekComplete = false;
972 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800973 }
974 } else {
975 mAudioPlayer->resume();
976 }
977 }
978
979 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700980 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800981 }
982
983 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800984 // Kick off video playback
985 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800986 }
987
Andreas Huberc1d5c922009-12-10 15:49:04 -0800988 if (deferredAudioSeek) {
989 // If there was a seek request while we were paused
990 // and we're just starting up again, honor the request now.
991 seekAudioIfNecessary_l();
992 }
993
Andreas Huber406a18b2010-02-18 16:45:13 -0800994 if (mFlags & AT_EOS) {
995 // Legacy behaviour, if a stream finishes playing and then
996 // is started again, we play from the start...
997 seekTo_l(0);
998 }
999
Andreas Huber27366fc2009-11-20 09:32:46 -08001000 return OK;
1001}
1002
Andreas Hubere3c01832010-08-16 08:49:37 -07001003void AwesomePlayer::notifyVideoSize_l() {
1004 sp<MetaData> meta = mVideoSource->getFormat();
1005
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001006 int32_t cropLeft, cropTop, cropRight, cropBottom;
1007 if (!meta->findRect(
1008 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
1009 int32_t width, height;
1010 CHECK(meta->findInt32(kKeyWidth, &width));
1011 CHECK(meta->findInt32(kKeyHeight, &height));
1012
1013 cropLeft = cropTop = 0;
1014 cropRight = width - 1;
1015 cropBottom = height - 1;
1016
1017 LOGV("got dimensions only %d x %d", width, height);
1018 } else {
1019 LOGV("got crop rect %d, %d, %d, %d",
1020 cropLeft, cropTop, cropRight, cropBottom);
1021 }
1022
1023 int32_t usableWidth = cropRight - cropLeft + 1;
1024 int32_t usableHeight = cropBottom - cropTop + 1;
Andreas Hubere3c01832010-08-16 08:49:37 -07001025
Andreas Huber940c8662010-11-16 15:26:30 -08001026 int32_t rotationDegrees;
1027 if (!mVideoTrack->getFormat()->findInt32(
1028 kKeyRotation, &rotationDegrees)) {
1029 rotationDegrees = 0;
1030 }
1031
1032 if (rotationDegrees == 90 || rotationDegrees == 270) {
1033 notifyListener_l(
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001034 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
Andreas Huber940c8662010-11-16 15:26:30 -08001035 } else {
1036 notifyListener_l(
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001037 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
Andreas Huber940c8662010-11-16 15:26:30 -08001038 }
Andreas Hubere3c01832010-08-16 08:49:37 -07001039}
1040
Andreas Huber27366fc2009-11-20 09:32:46 -08001041void AwesomePlayer::initRenderer_l() {
Andreas Huberc23dabf2010-11-16 13:05:53 -08001042 if (mSurface == NULL) {
1043 return;
1044 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001045
Andreas Huberc23dabf2010-11-16 13:05:53 -08001046 sp<MetaData> meta = mVideoSource->getFormat();
Andreas Huber27366fc2009-11-20 09:32:46 -08001047
Andreas Huberc23dabf2010-11-16 13:05:53 -08001048 int32_t format;
1049 const char *component;
1050 int32_t decodedWidth, decodedHeight;
1051 CHECK(meta->findInt32(kKeyColorFormat, &format));
1052 CHECK(meta->findCString(kKeyDecoderComponent, &component));
1053 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
1054 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
Andreas Hubera67d5382009-12-10 15:32:12 -08001055
Andreas Huber940c8662010-11-16 15:26:30 -08001056 int32_t rotationDegrees;
1057 if (!mVideoTrack->getFormat()->findInt32(
1058 kKeyRotation, &rotationDegrees)) {
1059 rotationDegrees = 0;
1060 }
1061
Andreas Huberc23dabf2010-11-16 13:05:53 -08001062 mVideoRenderer.clear();
Andreas Hubera67d5382009-12-10 15:32:12 -08001063
Andreas Huberc23dabf2010-11-16 13:05:53 -08001064 // Must ensure that mVideoRenderer's destructor is actually executed
1065 // before creating a new one.
1066 IPCThreadState::self()->flushCommands();
1067
1068 if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
1069 // Hardware decoders avoid the CPU color conversion by decoding
1070 // directly to ANativeBuffers, so we must use a renderer that
1071 // just pushes those buffers to the ANativeWindow.
Andreas Huber940c8662010-11-16 15:26:30 -08001072 mVideoRenderer =
1073 new AwesomeNativeWindowRenderer(mSurface, rotationDegrees);
Andreas Huberc23dabf2010-11-16 13:05:53 -08001074 } else {
1075 // Other decoders are instantiated locally and as a consequence
1076 // allocate their buffers in local address space. This renderer
1077 // then performs a color conversion and copy to get the data
1078 // into the ANativeBuffer.
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001079 mVideoRenderer = new AwesomeLocalRenderer(mSurface, meta);
Andreas Huber27366fc2009-11-20 09:32:46 -08001080 }
1081}
1082
1083status_t AwesomePlayer::pause() {
1084 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -07001085
1086 mFlags &= ~CACHE_UNDERRUN;
1087
Andreas Huber27366fc2009-11-20 09:32:46 -08001088 return pause_l();
1089}
1090
Andreas Huberc743f452010-10-05 10:25:34 -07001091status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001092 if (!(mFlags & PLAYING)) {
1093 return OK;
1094 }
1095
Andreas Huberb9e63832010-01-26 16:20:10 -08001096 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -08001097
1098 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -07001099 if (at_eos) {
1100 // If we played the audio stream to completion we
1101 // want to make sure that all samples remaining in the audio
1102 // track's queue are played out.
1103 mAudioPlayer->pause(true /* playPendingSamples */);
1104 } else {
1105 mAudioPlayer->pause();
1106 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001107 }
1108
1109 mFlags &= ~PLAYING;
1110
Gloria Wangd5770912010-06-22 13:55:38 -07001111 if (mDecryptHandle != NULL) {
1112 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1113 Playback::PAUSE, 0);
1114 }
1115
Andreas Huber27366fc2009-11-20 09:32:46 -08001116 return OK;
1117}
1118
1119bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -07001120 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -08001121}
1122
Andreas Hubere3c01832010-08-16 08:49:37 -07001123void AwesomePlayer::setSurface(const sp<Surface> &surface) {
1124 Mutex::Autolock autoLock(mLock);
1125
1126 mSurface = surface;
1127}
1128
Andreas Huber27366fc2009-11-20 09:32:46 -08001129void AwesomePlayer::setAudioSink(
1130 const sp<MediaPlayerBase::AudioSink> &audioSink) {
1131 Mutex::Autolock autoLock(mLock);
1132
1133 mAudioSink = audioSink;
1134}
1135
1136status_t AwesomePlayer::setLooping(bool shouldLoop) {
1137 Mutex::Autolock autoLock(mLock);
1138
1139 mFlags = mFlags & ~LOOPING;
1140
1141 if (shouldLoop) {
1142 mFlags |= LOOPING;
1143 }
1144
1145 return OK;
1146}
1147
1148status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -07001149 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001150
1151 if (mDurationUs < 0) {
1152 return UNKNOWN_ERROR;
1153 }
1154
1155 *durationUs = mDurationUs;
1156
1157 return OK;
1158}
1159
1160status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -07001161 if (mRTSPController != NULL) {
1162 *positionUs = mRTSPController->getNormalPlayTimeUs();
1163 }
1164 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -07001165 *positionUs = mSeekTimeUs;
1166 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -07001167 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001168 *positionUs = mVideoTimeUs;
1169 } else if (mAudioPlayer != NULL) {
1170 *positionUs = mAudioPlayer->getMediaTimeUs();
1171 } else {
1172 *positionUs = 0;
1173 }
1174
1175 return OK;
1176}
1177
1178status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -07001179 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001180 Mutex::Autolock autoLock(mLock);
1181 return seekTo_l(timeUs);
1182 }
1183
1184 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -08001185}
1186
Andreas Huber0c46b692010-10-08 15:21:08 -07001187// static
1188void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
1189 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
1190}
1191
1192void AwesomePlayer::onRTSPSeekDone() {
1193 notifyListener_l(MEDIA_SEEK_COMPLETE);
1194 mSeekNotificationSent = true;
1195}
1196
Andreas Huber27366fc2009-11-20 09:32:46 -08001197status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001198 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -07001199 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001200 return OK;
1201 }
1202
Andreas Huber4d61f602010-06-10 11:17:50 -07001203 if (mFlags & CACHE_UNDERRUN) {
1204 mFlags &= ~CACHE_UNDERRUN;
1205 play_l();
1206 }
1207
Andreas Huber27366fc2009-11-20 09:32:46 -08001208 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001209 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001210 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001211 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -08001212
1213 seekAudioIfNecessary_l();
1214
Andreas Huber8e2b9412010-03-31 09:40:15 -07001215 if (!(mFlags & PLAYING)) {
1216 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1217 " immediately.");
1218
1219 notifyListener_l(MEDIA_SEEK_COMPLETE);
1220 mSeekNotificationSent = true;
1221 }
1222
Andreas Huber27366fc2009-11-20 09:32:46 -08001223 return OK;
1224}
1225
1226void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -08001227 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001228 mAudioPlayer->seekTo(mSeekTimeUs);
1229
Andreas Huber70d10c02010-02-03 11:37:29 -08001230 mWatchForAudioSeekComplete = true;
1231 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001232 mSeekNotificationSent = false;
Gloria Wangd5770912010-06-22 13:55:38 -07001233
1234 if (mDecryptHandle != NULL) {
1235 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1236 Playback::PAUSE, 0);
1237 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1238 Playback::START, mSeekTimeUs / 1000);
1239 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001240 }
1241}
1242
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001243void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1244 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001245
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001246 mAudioTrack = source;
1247}
1248
1249status_t AwesomePlayer::initAudioDecoder() {
1250 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -08001251
1252 const char *mime;
1253 CHECK(meta->findCString(kKeyMIMEType, &mime));
1254
1255 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001256 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -08001257 } else {
1258 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001259 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -08001260 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001261 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -08001262 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001263
1264 if (mAudioSource != NULL) {
1265 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001266 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001267 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001268 if (mDurationUs < 0 || durationUs > mDurationUs) {
1269 mDurationUs = durationUs;
1270 }
1271 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001272
Andreas Huber3c78a1b2010-05-13 09:15:21 -07001273 status_t err = mAudioSource->start();
1274
1275 if (err != OK) {
1276 mAudioSource.clear();
1277 return err;
1278 }
Andreas Huberd0332ad2010-04-12 16:05:57 -07001279 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1280 // For legacy reasons we're simply going to ignore the absence
1281 // of an audio decoder for QCELP instead of aborting playback
1282 // altogether.
1283 return OK;
1284 }
Andreas Huberdc9927d2010-03-08 15:46:13 -08001285
Andreas Huber27366fc2009-11-20 09:32:46 -08001286 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1287}
1288
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001289void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1290 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001291
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001292 mVideoTrack = source;
1293}
1294
Andreas Huber4c19bf92010-09-08 14:32:20 -07001295status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001296 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001297 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -08001298 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -07001299 mVideoTrack,
Andreas Huber6a1f5f92010-11-15 09:03:03 -08001300 NULL, flags, USE_SURFACE_ALLOC ? mSurface : NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001301
1302 if (mVideoSource != NULL) {
1303 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001304 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001305 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001306 if (mDurationUs < 0 || durationUs > mDurationUs) {
1307 mDurationUs = durationUs;
1308 }
1309 }
1310
Andreas Huber1919e5a2010-05-20 10:37:06 -07001311 status_t err = mVideoSource->start();
1312
1313 if (err != OK) {
1314 mVideoSource.clear();
1315 return err;
1316 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001317 }
1318
1319 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1320}
1321
Andreas Huber4d450a82010-10-19 09:34:44 -07001322void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1323 if (!mSeeking) {
1324 return;
1325 }
1326
1327 if (mAudioPlayer != NULL) {
Jamie Gennis6913c612010-10-20 15:55:43 -07001328 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
Andreas Huber4d450a82010-10-19 09:34:44 -07001329
1330 // If we don't have a video time, seek audio to the originally
1331 // requested seek time instead.
1332
1333 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1334 mAudioPlayer->resume();
1335 mWatchForAudioSeekComplete = true;
1336 mWatchForAudioEOS = true;
1337 } else if (!mSeekNotificationSent) {
1338 // If we're playing video only, report seek complete now,
1339 // otherwise audio player will notify us later.
1340 notifyListener_l(MEDIA_SEEK_COMPLETE);
1341 }
1342
1343 mFlags |= FIRST_FRAME;
1344 mSeeking = false;
1345 mSeekNotificationSent = false;
Gloria Wang3f9a8192010-10-29 14:50:17 -07001346
1347 if (mDecryptHandle != NULL) {
1348 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1349 Playback::PAUSE, 0);
1350 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1351 Playback::START, videoTimeUs / 1000);
1352 }
Andreas Huber4d450a82010-10-19 09:34:44 -07001353}
1354
Andreas Huber6be780e2010-02-08 14:40:30 -08001355void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001356 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001357 if (!mVideoEventPending) {
1358 // The event has been cancelled in reset_l() but had already
1359 // been scheduled for execution at that time.
1360 return;
1361 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001362 mVideoEventPending = false;
1363
1364 if (mSeeking) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001365 if (mVideoBuffer) {
1366 mVideoBuffer->release();
1367 mVideoBuffer = NULL;
1368 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001369
1370 if (mCachedSource != NULL && mAudioSource != NULL) {
1371 // We're going to seek the video source first, followed by
1372 // the audio source.
1373 // In order to avoid jumps in the DataSource offset caused by
1374 // the audio codec prefetching data from the old locations
1375 // while the video codec is already reading data from the new
1376 // locations, we'll "pause" the audio source, causing it to
1377 // stop reading input data until a subsequent seek.
1378
1379 if (mAudioPlayer != NULL) {
1380 mAudioPlayer->pause();
1381 }
1382 mAudioSource->pause();
1383 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001384 }
1385
1386 if (!mVideoBuffer) {
1387 MediaSource::ReadOptions options;
1388 if (mSeeking) {
1389 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1390
Andreas Huber6624c9f2010-07-20 15:04:28 -07001391 options.setSeekTo(
1392 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001393 }
1394 for (;;) {
1395 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001396 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001397
1398 if (err != OK) {
Andreas Huber52b52cd2010-11-23 11:41:34 -08001399 CHECK(mVideoBuffer == NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001400
1401 if (err == INFO_FORMAT_CHANGED) {
1402 LOGV("VideoSource signalled format change.");
1403
Andreas Hubere3c01832010-08-16 08:49:37 -07001404 notifyVideoSize_l();
1405
Andreas Huber7085b6842010-02-03 16:02:02 -08001406 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001407 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001408 initRenderer_l();
1409 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001410 continue;
1411 }
1412
Andreas Huber4d450a82010-10-19 09:34:44 -07001413 // So video playback is complete, but we may still have
1414 // a seek request pending that needs to be applied
1415 // to the audio track.
1416 if (mSeeking) {
1417 LOGV("video stream ended while seeking!");
1418 }
1419 finishSeekIfNecessary(-1);
1420
Andreas Huber971305d2010-07-07 13:35:27 -07001421 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001422 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001423 return;
1424 }
1425
Andreas Hubera67d5382009-12-10 15:32:12 -08001426 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001427 // Some decoders, notably the PV AVC software decoder
1428 // return spurious empty buffers that we just want to ignore.
1429
Andreas Hubera67d5382009-12-10 15:32:12 -08001430 mVideoBuffer->release();
1431 mVideoBuffer = NULL;
1432 continue;
1433 }
1434
Andreas Huber27366fc2009-11-20 09:32:46 -08001435 break;
1436 }
1437 }
1438
1439 int64_t timeUs;
1440 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1441
Andreas Huber252573c2010-03-26 10:17:17 -07001442 {
1443 Mutex::Autolock autoLock(mMiscStateLock);
1444 mVideoTimeUs = timeUs;
1445 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001446
Andreas Huber614d22c2010-10-29 15:47:52 -07001447 bool wasSeeking = mSeeking;
Andreas Huber4d450a82010-10-19 09:34:44 -07001448 finishSeekIfNecessary(timeUs);
Andreas Huber27366fc2009-11-20 09:32:46 -08001449
Andreas Huber971305d2010-07-07 13:35:27 -07001450 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1451
Andreas Huber27366fc2009-11-20 09:32:46 -08001452 if (mFlags & FIRST_FRAME) {
1453 mFlags &= ~FIRST_FRAME;
1454
Andreas Huber971305d2010-07-07 13:35:27 -07001455 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001456 }
1457
1458 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001459 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001460 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1461 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1462 }
1463
Andreas Huber971305d2010-07-07 13:35:27 -07001464 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001465
1466 int64_t latenessUs = nowUs - timeUs;
1467
Andreas Huber614d22c2010-10-29 15:47:52 -07001468 if (wasSeeking) {
1469 // Let's display the first frame after seeking right away.
1470 latenessUs = 0;
1471 }
1472
Andreas Huberf88f8442010-08-10 11:18:36 -07001473 if (mRTPSession != NULL) {
1474 // We'll completely ignore timestamps for gtalk videochat
1475 // and we'll play incoming video as fast as we get it.
1476 latenessUs = 0;
1477 }
1478
Andreas Huber24b0a952009-11-23 14:02:00 -08001479 if (latenessUs > 40000) {
1480 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001481 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001482
1483 mVideoBuffer->release();
1484 mVideoBuffer = NULL;
1485
1486 postVideoEvent_l();
1487 return;
1488 }
1489
1490 if (latenessUs < -10000) {
1491 // We're more than 10ms early.
1492
1493 postVideoEvent_l(10000);
1494 return;
1495 }
1496
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001497 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1498 mVideoRendererIsPreview = false;
1499
Andreas Huber7085b6842010-02-03 16:02:02 -08001500 initRenderer_l();
1501 }
1502
1503 if (mVideoRenderer != NULL) {
1504 mVideoRenderer->render(mVideoBuffer);
1505 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001506
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001507 mVideoBuffer->release();
Andreas Huber27366fc2009-11-20 09:32:46 -08001508 mVideoBuffer = NULL;
1509
1510 postVideoEvent_l();
1511}
1512
1513void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1514 if (mVideoEventPending) {
1515 return;
1516 }
1517
1518 mVideoEventPending = true;
1519 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1520}
1521
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001522void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001523 if (mStreamDoneEventPending) {
1524 return;
1525 }
1526 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001527
1528 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001529 mQueue.postEvent(mStreamDoneEvent);
1530}
1531
Andreas Huberb9e63832010-01-26 16:20:10 -08001532void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001533 if (mBufferingEventPending) {
1534 return;
1535 }
1536 mBufferingEventPending = true;
1537 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1538}
1539
Andreas Huber70d10c02010-02-03 11:37:29 -08001540void AwesomePlayer::postCheckAudioStatusEvent_l() {
1541 if (mAudioStatusEventPending) {
1542 return;
1543 }
1544 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001545 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001546}
1547
1548void AwesomePlayer::onCheckAudioStatus() {
1549 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001550 if (!mAudioStatusEventPending) {
1551 // Event was dispatched and while we were blocking on the mutex,
1552 // has already been cancelled.
1553 return;
1554 }
1555
Andreas Huber70d10c02010-02-03 11:37:29 -08001556 mAudioStatusEventPending = false;
1557
1558 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1559 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001560
1561 if (!mSeekNotificationSent) {
1562 notifyListener_l(MEDIA_SEEK_COMPLETE);
1563 mSeekNotificationSent = true;
1564 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001565
1566 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001567 }
1568
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001569 status_t finalStatus;
1570 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001571 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001572 mFlags |= AUDIO_AT_EOS;
1573 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001574 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001575 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001576}
1577
Andreas Huber6be780e2010-02-08 14:40:30 -08001578status_t AwesomePlayer::prepare() {
1579 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001580 return prepare_l();
1581}
Andreas Huber6be780e2010-02-08 14:40:30 -08001582
Andreas Huberffdf4782010-02-09 14:05:43 -08001583status_t AwesomePlayer::prepare_l() {
1584 if (mFlags & PREPARED) {
1585 return OK;
1586 }
1587
1588 if (mFlags & PREPARING) {
1589 return UNKNOWN_ERROR;
1590 }
1591
1592 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001593 status_t err = prepareAsync_l();
1594
1595 if (err != OK) {
1596 return err;
1597 }
1598
Andreas Huberffdf4782010-02-09 14:05:43 -08001599 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001600 mPreparedCondition.wait(mLock);
1601 }
1602
Andreas Huberffdf4782010-02-09 14:05:43 -08001603 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001604}
1605
1606status_t AwesomePlayer::prepareAsync() {
1607 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001608
1609 if (mFlags & PREPARING) {
1610 return UNKNOWN_ERROR; // async prepare already pending
1611 }
1612
1613 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001614 return prepareAsync_l();
1615}
1616
1617status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001618 if (mFlags & PREPARING) {
1619 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001620 }
1621
Andreas Huber406a18b2010-02-18 16:45:13 -08001622 if (!mQueueStarted) {
1623 mQueue.start();
1624 mQueueStarted = true;
1625 }
1626
Andreas Huberffdf4782010-02-09 14:05:43 -08001627 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001628 mAsyncPrepareEvent = new AwesomeEvent(
1629 this, &AwesomePlayer::onPrepareAsyncEvent);
1630
1631 mQueue.postEvent(mAsyncPrepareEvent);
1632
1633 return OK;
1634}
1635
Andreas Huberffdf4782010-02-09 14:05:43 -08001636status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001637 sp<DataSource> dataSource;
1638
1639 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001640 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001641
1642 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001643 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001644 mLock.lock();
1645
1646 if (err != OK) {
1647 mConnectingDataSource.clear();
1648
1649 LOGI("mConnectingDataSource->connect() returned %d", err);
1650 return err;
1651 }
1652
Andreas Huber4d61f602010-06-10 11:17:50 -07001653#if 0
1654 mCachedSource = new NuCachedSource2(
1655 new ThrottledSource(
1656 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1657#else
1658 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1659#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001660 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001661
1662 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001663 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1664 String8 uri("http://");
1665 uri.append(mUri.string() + 11);
1666
Andreas Huberb5590842010-12-03 16:12:25 -08001667 if (mLooper == NULL) {
1668 mLooper = new ALooper;
1669 mLooper->setName("httplive");
1670 mLooper->start();
1671 }
Andreas Huber202348e2010-06-07 14:35:29 -07001672
Andreas Huberb5590842010-12-03 16:12:25 -08001673 mLiveSession = new LiveSession;
1674 mLooper->registerHandler(mLiveSession);
1675
1676 mLiveSession->connect(uri.string());
1677 dataSource = mLiveSession->getDataSource();
Andreas Huber202348e2010-06-07 14:35:29 -07001678
1679 sp<MediaExtractor> extractor =
1680 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001681
Andreas Huber54d09722010-10-12 11:34:37 -07001682 static_cast<MPEG2TSExtractor *>(extractor.get())
Andreas Huberb5590842010-12-03 16:12:25 -08001683 ->setLiveSession(mLiveSession);
Andreas Huber54d09722010-10-12 11:34:37 -07001684
Andreas Huber4d61f602010-06-10 11:17:50 -07001685 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001686 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001687 if (mLooper == NULL) {
1688 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001689 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001690 mLooper->start(
1691 false /* runOnCallingThread */,
1692 false /* canCallJava */,
1693 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001694 }
1695
Mike Dodd8741dfa2010-08-12 16:04:35 -07001696 const char *startOfCodecString = &mUri.string()[13];
1697 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1698 if (startOfSlash1 == NULL) {
1699 return BAD_VALUE;
1700 }
1701 const char *startOfWidthString = &startOfSlash1[1];
1702 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1703 if (startOfSlash2 == NULL) {
1704 return BAD_VALUE;
1705 }
1706 const char *startOfHeightString = &startOfSlash2[1];
1707
1708 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1709 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1710 String8 heightString(startOfHeightString);
1711
Andreas Huber57648e42010-08-04 10:14:30 -07001712#if 0
1713 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1714 mLooper->registerHandler(mRTPPusher);
1715
1716 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1717 mLooper->registerHandler(mRTCPPusher);
1718#endif
1719
1720 mRTPSession = new ARTPSession;
1721 mLooper->registerHandler(mRTPSession);
1722
1723#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001724 // My AMR SDP
1725 static const char *raw =
1726 "v=0\r\n"
1727 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1728 "s=QuickTime\r\n"
1729 "t=0 0\r\n"
1730 "a=range:npt=0-315\r\n"
1731 "a=isma-compliance:2,2.0,2\r\n"
1732 "m=audio 5434 RTP/AVP 97\r\n"
1733 "c=IN IP4 127.0.0.1\r\n"
1734 "b=AS:30\r\n"
1735 "a=rtpmap:97 AMR/8000/1\r\n"
1736 "a=fmtp:97 octet-align\r\n";
1737#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001738 String8 sdp;
1739 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001740 "v=0\r\n"
1741 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1742 "s=QuickTime\r\n"
1743 "t=0 0\r\n"
1744 "a=range:npt=0-315\r\n"
1745 "a=isma-compliance:2,2.0,2\r\n"
1746 "m=video 5434 RTP/AVP 97\r\n"
1747 "c=IN IP4 127.0.0.1\r\n"
1748 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001749 "a=rtpmap:97 %s/90000\r\n"
1750 "a=cliprect:0,0,%s,%s\r\n"
1751 "a=framesize:97 %s-%s\r\n",
1752
1753 codecString.string(),
1754 heightString.string(), widthString.string(),
1755 widthString.string(), heightString.string()
1756 );
1757 const char *raw = sdp.string();
1758
Andreas Huber57648e42010-08-04 10:14:30 -07001759#endif
1760
1761 sp<ASessionDescription> desc = new ASessionDescription;
1762 CHECK(desc->setTo(raw, strlen(raw)));
1763
1764 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1765
1766 if (mRTPPusher != NULL) {
1767 mRTPPusher->start();
1768 }
1769
1770 if (mRTCPPusher != NULL) {
1771 mRTCPPusher->start();
1772 }
1773
1774 CHECK_EQ(mRTPSession->countTracks(), 1u);
1775 sp<MediaSource> source = mRTPSession->trackAt(0);
1776
1777#if 0
1778 bool eos;
1779 while (((APacketSource *)source.get())
1780 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1781 usleep(100000ll);
1782 }
1783#endif
1784
1785 const char *mime;
1786 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1787
1788 if (!strncasecmp("video/", mime, 6)) {
1789 setVideoSource(source);
1790 } else {
1791 CHECK(!strncasecmp("audio/", mime, 6));
1792 setAudioSource(source);
1793 }
1794
1795 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1796
1797 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001798 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1799 if (mLooper == NULL) {
1800 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001801 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001802 mLooper->start();
1803 }
1804 mRTSPController = new ARTSPController(mLooper);
1805 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001806
Andreas Huber7a747b82010-06-07 15:19:40 -07001807 LOGI("ARTSPController::connect returned %d", err);
1808
1809 if (err != OK) {
1810 mRTSPController.clear();
1811 return err;
1812 }
1813
1814 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001815 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001816 } else {
1817 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1818 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001819
1820 if (dataSource == NULL) {
1821 return UNKNOWN_ERROR;
1822 }
1823
1824 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1825
1826 if (extractor == NULL) {
1827 return UNKNOWN_ERROR;
1828 }
1829
Gloria Wangd5770912010-06-22 13:55:38 -07001830 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangc2c22e72010-11-01 15:53:16 -07001831 if (mDecryptHandle != NULL) {
1832 if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
1833 if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) {
1834 LOGD("Setting mCachedSource to NULL for WVM\n");
1835 mCachedSource.clear();
1836 }
1837 } else {
1838 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
1839 }
Gloria Wangd5770912010-06-22 13:55:38 -07001840 }
1841
Andreas Huberffdf4782010-02-09 14:05:43 -08001842 return setDataSource_l(extractor);
1843}
1844
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001845void AwesomePlayer::abortPrepare(status_t err) {
1846 CHECK(err != OK);
1847
1848 if (mIsAsyncPrepare) {
1849 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1850 }
1851
1852 mPrepareResult = err;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001853 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001854 mAsyncPrepareEvent = NULL;
1855 mPreparedCondition.broadcast();
1856}
1857
Andreas Huberf71daba2010-03-24 09:24:40 -07001858// static
1859bool AwesomePlayer::ContinuePreparation(void *cookie) {
1860 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1861
1862 return (me->mFlags & PREPARE_CANCELLED) == 0;
1863}
1864
Andreas Huber6be780e2010-02-08 14:40:30 -08001865void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001866 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001867
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001868 if (mFlags & PREPARE_CANCELLED) {
1869 LOGI("prepare was cancelled before doing anything");
1870 abortPrepare(UNKNOWN_ERROR);
1871 return;
1872 }
1873
1874 if (mUri.size() > 0) {
1875 status_t err = finishSetDataSource_l();
1876
1877 if (err != OK) {
1878 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001879 return;
1880 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001881 }
1882
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001883 if (mVideoTrack != NULL && mVideoSource == NULL) {
1884 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001885
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001886 if (err != OK) {
1887 abortPrepare(err);
1888 return;
1889 }
1890 }
1891
1892 if (mAudioTrack != NULL && mAudioSource == NULL) {
1893 status_t err = initAudioDecoder();
1894
1895 if (err != OK) {
1896 abortPrepare(err);
1897 return;
1898 }
1899 }
1900
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001901 mFlags |= PREPARING_CONNECTED;
1902
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001903 if (mCachedSource != NULL || mRTSPController != NULL) {
1904 postBufferingEvent_l();
1905 } else {
1906 finishAsyncPrepare_l();
1907 }
1908}
1909
1910void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001911 if (mIsAsyncPrepare) {
Andreas Hubere3c01832010-08-16 08:49:37 -07001912 if (mVideoSource == NULL) {
Andreas Huberffdf4782010-02-09 14:05:43 -08001913 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1914 } else {
Andreas Hubere3c01832010-08-16 08:49:37 -07001915 notifyVideoSize_l();
Andreas Huberffdf4782010-02-09 14:05:43 -08001916 }
1917
1918 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001919 }
1920
Andreas Huberffdf4782010-02-09 14:05:43 -08001921 mPrepareResult = OK;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001922 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001923 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001924 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001925 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001926}
1927
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001928uint32_t AwesomePlayer::flags() const {
1929 return mExtractorFlags;
1930}
1931
Andreas Huber2b359ed2010-09-28 11:56:39 -07001932void AwesomePlayer::postAudioEOS() {
1933 postCheckAudioStatusEvent_l();
1934}
1935
1936void AwesomePlayer::postAudioSeekComplete() {
1937 postCheckAudioStatusEvent_l();
1938}
1939
Andreas Huber27366fc2009-11-20 09:32:46 -08001940} // namespace android