blob: 8ebbe6c42bd94f51d90f405444737786e260db16 [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 Huber52b52cd2010-11-23 11:41:34 -080037#include <binder/MemoryDealer.h>
38#include <media/IStreamSource.h>
39#include <media/stagefright/foundation/hexdump.h>
40#include <media/stagefright/foundation/ADebug.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080041#include <media/stagefright/AudioPlayer.h>
42#include <media/stagefright/DataSource.h>
43#include <media/stagefright/FileSource.h>
44#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080045#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080046#include <media/stagefright/MediaExtractor.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080047#include <media/stagefright/MediaSource.h>
48#include <media/stagefright/MetaData.h>
49#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080050
Andreas Hubere3c01832010-08-16 08:49:37 -070051#include <surfaceflinger/Surface.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080052
Andreas Huber7a747b82010-06-07 15:19:40 -070053#include <media/stagefright/foundation/ALooper.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 Huber57648e42010-08-04 10:14:30 -0700637 mRTPPusher.clear();
638 mRTCPPusher.clear();
639 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700640
Andreas Huber27366fc2009-11-20 09:32:46 -0800641 if (mVideoSource != NULL) {
642 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800643
644 // The following hack is necessary to ensure that the OMX
645 // component is completely released by the time we may try
646 // to instantiate it again.
647 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800648 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800649 while (tmp.promote() != NULL) {
650 usleep(1000);
651 }
652 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800653 }
654
Andreas Huber27366fc2009-11-20 09:32:46 -0800655 mDurationUs = -1;
656 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700657 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800658 mTimeSourceDeltaUs = 0;
659 mVideoTimeUs = 0;
660
661 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700662 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800663 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800664
Andreas Huberffdf4782010-02-09 14:05:43 -0800665 mUri.setTo("");
666 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800667
668 mFileSource.clear();
669
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700670 mBitrate = -1;
Andreas Huber27366fc2009-11-20 09:32:46 -0800671}
672
Andreas Huber6be780e2010-02-08 14:40:30 -0800673void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800674 if (mListener != NULL) {
675 sp<MediaPlayerBase> listener = mListener.promote();
676
677 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800678 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800679 }
680 }
681}
682
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700683bool AwesomePlayer::getBitrate(int64_t *bitrate) {
James Dongb1262a82010-11-16 14:04:54 -0800684 off64_t size;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700685 if (mDurationUs >= 0 && mCachedSource != NULL
686 && mCachedSource->getSize(&size) == OK) {
687 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
688 return true;
689 }
690
691 if (mBitrate >= 0) {
692 *bitrate = mBitrate;
693 return true;
694 }
695
696 *bitrate = 0;
697
698 return false;
699}
700
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700701// Returns true iff cached duration is available/applicable.
702bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700703 int64_t bitrate;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700704
705 if (mRTSPController != NULL) {
706 *durationUs = mRTSPController->getQueueDurationUs(eos);
707 return true;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700708 } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700709 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
710 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
711 return true;
712 }
713
714 return false;
715}
716
Andreas Huber10b920c2010-11-11 15:37:17 -0800717void AwesomePlayer::ensureCacheIsFetching_l() {
718 if (mCachedSource != NULL) {
719 mCachedSource->resumeFetchingIfNecessary();
720 }
721}
722
Andreas Huberb9e63832010-01-26 16:20:10 -0800723void AwesomePlayer::onBufferingUpdate() {
724 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800725 if (!mBufferingEventPending) {
726 return;
727 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800728 mBufferingEventPending = false;
729
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700730 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700731 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700732 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700733
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700734 if (eos) {
735 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700736 if (mFlags & PREPARING) {
737 LOGV("cache has reached EOS, prepare is done.");
738 finishAsyncPrepare_l();
739 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700740 } else {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700741 int64_t bitrate;
742 if (getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700743 size_t cachedSize = mCachedSource->cachedSize();
744 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
745
746 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
747 if (percentage > 100) {
748 percentage = 100;
749 }
750
751 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
752 } else {
753 // We don't know the bitrate of the stream, use absolute size
754 // limits to maintain the cache.
755
Andreas Huber54d09722010-10-12 11:34:37 -0700756 const size_t kLowWaterMarkBytes = 40000;
757 const size_t kHighWaterMarkBytes = 200000;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700758
759 if ((mFlags & PLAYING) && !eos
760 && (cachedDataRemaining < kLowWaterMarkBytes)) {
761 LOGI("cache is running low (< %d) , pausing.",
762 kLowWaterMarkBytes);
763 mFlags |= CACHE_UNDERRUN;
764 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800765 ensureCacheIsFetching_l();
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700766 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
767 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
768 if (mFlags & CACHE_UNDERRUN) {
769 LOGI("cache has filled up (> %d), resuming.",
770 kHighWaterMarkBytes);
771 mFlags &= ~CACHE_UNDERRUN;
772 play_l();
773 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
774 } else if (mFlags & PREPARING) {
775 LOGV("cache has filled up (> %d), prepare is done",
776 kHighWaterMarkBytes);
777 finishAsyncPrepare_l();
778 }
779 }
780 }
781 }
782 }
783
784 int64_t cachedDurationUs;
785 bool eos;
786 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber10b920c2010-11-11 15:37:17 -0800787 LOGV("cachedDurationUs = %.2f secs, eos=%d",
788 cachedDurationUs / 1E6, eos);
789
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700790 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700791 && (cachedDurationUs < kLowWaterMarkUs)) {
792 LOGI("cache is running low (%.2f secs) , pausing.",
793 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700794 mFlags |= CACHE_UNDERRUN;
795 pause_l();
Andreas Huber10b920c2010-11-11 15:37:17 -0800796 ensureCacheIsFetching_l();
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700797 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700798 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
799 if (mFlags & CACHE_UNDERRUN) {
800 LOGI("cache has filled up (%.2f secs), resuming.",
801 cachedDurationUs / 1E6);
802 mFlags &= ~CACHE_UNDERRUN;
803 play_l();
804 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
805 } else if (mFlags & PREPARING) {
806 LOGV("cache has filled up (%.2f secs), prepare is done",
807 cachedDurationUs / 1E6);
808 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700809 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700810 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800811 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700812
Andreas Huber4d61f602010-06-10 11:17:50 -0700813 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800814}
815
Andreas Huber4c19bf92010-09-08 14:32:20 -0700816void AwesomePlayer::partial_reset_l() {
817 // Only reset the video renderer and shut down the video decoder.
818 // Then instantiate a new video decoder and resume video playback.
819
820 mVideoRenderer.clear();
821
Andreas Huber4c19bf92010-09-08 14:32:20 -0700822 if (mVideoBuffer) {
823 mVideoBuffer->release();
824 mVideoBuffer = NULL;
825 }
826
827 {
828 mVideoSource->stop();
829
830 // The following hack is necessary to ensure that the OMX
831 // component is completely released by the time we may try
832 // to instantiate it again.
833 wp<MediaSource> tmp = mVideoSource;
834 mVideoSource.clear();
835 while (tmp.promote() != NULL) {
836 usleep(1000);
837 }
838 IPCThreadState::self()->flushCommands();
839 }
840
Andreas Huber52b52cd2010-11-23 11:41:34 -0800841 CHECK_EQ((status_t)OK,
842 initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
Andreas Huber4c19bf92010-09-08 14:32:20 -0700843}
844
Andreas Huber27366fc2009-11-20 09:32:46 -0800845void AwesomePlayer::onStreamDone() {
846 // Posted whenever any stream finishes playing.
847
848 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800849 if (!mStreamDoneEventPending) {
850 return;
851 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800852 mStreamDoneEventPending = false;
853
Andreas Huber4c19bf92010-09-08 14:32:20 -0700854 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
855 // This special status is returned because an http live stream's
856 // video stream switched to a different bandwidth at this point
857 // and future data may have been encoded using different parameters.
858 // This requires us to shutdown the video decoder and reinstantiate
859 // a fresh one.
860
861 LOGV("INFO_DISCONTINUITY");
862
863 CHECK(mVideoSource != NULL);
864
865 partial_reset_l();
866 postVideoEvent_l();
867 return;
868 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700869 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
870
871 notifyListener_l(
872 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
873
Andreas Huberc743f452010-10-05 10:25:34 -0700874 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700875
876 mFlags |= AT_EOS;
877 return;
878 }
879
880 const bool allDone =
881 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
882 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
883
884 if (!allDone) {
885 return;
886 }
887
Andreas Huber9fee0b22010-09-03 14:09:21 -0700888 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800889 seekTo_l(0);
890
Andreas Huber7085b6842010-02-03 16:02:02 -0800891 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800892 postVideoEvent_l();
893 }
894 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700895 LOGV("MEDIA_PLAYBACK_COMPLETE");
896 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800897
Andreas Huberc743f452010-10-05 10:25:34 -0700898 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800899
900 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800901 }
902}
903
904status_t AwesomePlayer::play() {
905 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700906
907 mFlags &= ~CACHE_UNDERRUN;
908
Andreas Huberba7ec912010-02-12 10:42:02 -0800909 return play_l();
910}
Andreas Huber27366fc2009-11-20 09:32:46 -0800911
Andreas Huberba7ec912010-02-12 10:42:02 -0800912status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800913 if (mFlags & PLAYING) {
914 return OK;
915 }
916
Andreas Huberffdf4782010-02-09 14:05:43 -0800917 if (!(mFlags & PREPARED)) {
918 status_t err = prepare_l();
919
920 if (err != OK) {
921 return err;
922 }
923 }
924
Andreas Huber27366fc2009-11-20 09:32:46 -0800925 mFlags |= PLAYING;
926 mFlags |= FIRST_FRAME;
927
Andreas Huberc1d5c922009-12-10 15:49:04 -0800928 bool deferredAudioSeek = false;
929
Gloria Wang95dbffb2010-11-04 17:38:39 -0700930 if (mDecryptHandle != NULL) {
931 int64_t position;
932 getPosition(&position);
933 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
934 Playback::START, position / 1000);
935 }
936
Andreas Huber27366fc2009-11-20 09:32:46 -0800937 if (mAudioSource != NULL) {
938 if (mAudioPlayer == NULL) {
939 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700940 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800941 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800942
943 // We've already started the MediaSource in order to enable
944 // the prefetcher to read its data.
945 status_t err = mAudioPlayer->start(
946 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800947
948 if (err != OK) {
949 delete mAudioPlayer;
950 mAudioPlayer = NULL;
951
952 mFlags &= ~(PLAYING | FIRST_FRAME);
953
Gloria Wang95dbffb2010-11-04 17:38:39 -0700954 if (mDecryptHandle != NULL) {
955 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
956 Playback::STOP, 0);
957 }
958
Andreas Huber62eac002010-01-29 13:24:58 -0800959 return err;
960 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800961
Andreas Huber27366fc2009-11-20 09:32:46 -0800962 mTimeSource = mAudioPlayer;
963
Andreas Huberc1d5c922009-12-10 15:49:04 -0800964 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800965
966 mWatchForAudioSeekComplete = false;
967 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800968 }
969 } else {
970 mAudioPlayer->resume();
971 }
972 }
973
974 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700975 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800976 }
977
978 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800979 // Kick off video playback
980 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800981 }
982
Andreas Huberc1d5c922009-12-10 15:49:04 -0800983 if (deferredAudioSeek) {
984 // If there was a seek request while we were paused
985 // and we're just starting up again, honor the request now.
986 seekAudioIfNecessary_l();
987 }
988
Andreas Huber406a18b2010-02-18 16:45:13 -0800989 if (mFlags & AT_EOS) {
990 // Legacy behaviour, if a stream finishes playing and then
991 // is started again, we play from the start...
992 seekTo_l(0);
993 }
994
Andreas Huber27366fc2009-11-20 09:32:46 -0800995 return OK;
996}
997
Andreas Hubere3c01832010-08-16 08:49:37 -0700998void AwesomePlayer::notifyVideoSize_l() {
999 sp<MetaData> meta = mVideoSource->getFormat();
1000
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001001 int32_t cropLeft, cropTop, cropRight, cropBottom;
1002 if (!meta->findRect(
1003 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
1004 int32_t width, height;
1005 CHECK(meta->findInt32(kKeyWidth, &width));
1006 CHECK(meta->findInt32(kKeyHeight, &height));
1007
1008 cropLeft = cropTop = 0;
1009 cropRight = width - 1;
1010 cropBottom = height - 1;
1011
1012 LOGV("got dimensions only %d x %d", width, height);
1013 } else {
1014 LOGV("got crop rect %d, %d, %d, %d",
1015 cropLeft, cropTop, cropRight, cropBottom);
1016 }
1017
1018 int32_t usableWidth = cropRight - cropLeft + 1;
1019 int32_t usableHeight = cropBottom - cropTop + 1;
Andreas Hubere3c01832010-08-16 08:49:37 -07001020
Andreas Huber940c8662010-11-16 15:26:30 -08001021 int32_t rotationDegrees;
1022 if (!mVideoTrack->getFormat()->findInt32(
1023 kKeyRotation, &rotationDegrees)) {
1024 rotationDegrees = 0;
1025 }
1026
1027 if (rotationDegrees == 90 || rotationDegrees == 270) {
1028 notifyListener_l(
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001029 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth);
Andreas Huber940c8662010-11-16 15:26:30 -08001030 } else {
1031 notifyListener_l(
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001032 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight);
Andreas Huber940c8662010-11-16 15:26:30 -08001033 }
Andreas Hubere3c01832010-08-16 08:49:37 -07001034}
1035
Andreas Huber27366fc2009-11-20 09:32:46 -08001036void AwesomePlayer::initRenderer_l() {
Andreas Huberc23dabf2010-11-16 13:05:53 -08001037 if (mSurface == NULL) {
1038 return;
1039 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001040
Andreas Huberc23dabf2010-11-16 13:05:53 -08001041 sp<MetaData> meta = mVideoSource->getFormat();
Andreas Huber27366fc2009-11-20 09:32:46 -08001042
Andreas Huberc23dabf2010-11-16 13:05:53 -08001043 int32_t format;
1044 const char *component;
1045 int32_t decodedWidth, decodedHeight;
1046 CHECK(meta->findInt32(kKeyColorFormat, &format));
1047 CHECK(meta->findCString(kKeyDecoderComponent, &component));
1048 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
1049 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
Andreas Hubera67d5382009-12-10 15:32:12 -08001050
Andreas Huber940c8662010-11-16 15:26:30 -08001051 int32_t rotationDegrees;
1052 if (!mVideoTrack->getFormat()->findInt32(
1053 kKeyRotation, &rotationDegrees)) {
1054 rotationDegrees = 0;
1055 }
1056
Andreas Huberc23dabf2010-11-16 13:05:53 -08001057 mVideoRenderer.clear();
Andreas Hubera67d5382009-12-10 15:32:12 -08001058
Andreas Huberc23dabf2010-11-16 13:05:53 -08001059 // Must ensure that mVideoRenderer's destructor is actually executed
1060 // before creating a new one.
1061 IPCThreadState::self()->flushCommands();
1062
1063 if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
1064 // Hardware decoders avoid the CPU color conversion by decoding
1065 // directly to ANativeBuffers, so we must use a renderer that
1066 // just pushes those buffers to the ANativeWindow.
Andreas Huber940c8662010-11-16 15:26:30 -08001067 mVideoRenderer =
1068 new AwesomeNativeWindowRenderer(mSurface, rotationDegrees);
Andreas Huberc23dabf2010-11-16 13:05:53 -08001069 } else {
1070 // Other decoders are instantiated locally and as a consequence
1071 // allocate their buffers in local address space. This renderer
1072 // then performs a color conversion and copy to get the data
1073 // into the ANativeBuffer.
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001074 mVideoRenderer = new AwesomeLocalRenderer(mSurface, meta);
Andreas Huber27366fc2009-11-20 09:32:46 -08001075 }
1076}
1077
1078status_t AwesomePlayer::pause() {
1079 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -07001080
1081 mFlags &= ~CACHE_UNDERRUN;
1082
Andreas Huber27366fc2009-11-20 09:32:46 -08001083 return pause_l();
1084}
1085
Andreas Huberc743f452010-10-05 10:25:34 -07001086status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001087 if (!(mFlags & PLAYING)) {
1088 return OK;
1089 }
1090
Andreas Huberb9e63832010-01-26 16:20:10 -08001091 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -08001092
1093 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -07001094 if (at_eos) {
1095 // If we played the audio stream to completion we
1096 // want to make sure that all samples remaining in the audio
1097 // track's queue are played out.
1098 mAudioPlayer->pause(true /* playPendingSamples */);
1099 } else {
1100 mAudioPlayer->pause();
1101 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001102 }
1103
1104 mFlags &= ~PLAYING;
1105
Gloria Wangd5770912010-06-22 13:55:38 -07001106 if (mDecryptHandle != NULL) {
1107 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1108 Playback::PAUSE, 0);
1109 }
1110
Andreas Huber27366fc2009-11-20 09:32:46 -08001111 return OK;
1112}
1113
1114bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -07001115 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -08001116}
1117
Andreas Hubere3c01832010-08-16 08:49:37 -07001118void AwesomePlayer::setSurface(const sp<Surface> &surface) {
1119 Mutex::Autolock autoLock(mLock);
1120
1121 mSurface = surface;
1122}
1123
Andreas Huber27366fc2009-11-20 09:32:46 -08001124void AwesomePlayer::setAudioSink(
1125 const sp<MediaPlayerBase::AudioSink> &audioSink) {
1126 Mutex::Autolock autoLock(mLock);
1127
1128 mAudioSink = audioSink;
1129}
1130
1131status_t AwesomePlayer::setLooping(bool shouldLoop) {
1132 Mutex::Autolock autoLock(mLock);
1133
1134 mFlags = mFlags & ~LOOPING;
1135
1136 if (shouldLoop) {
1137 mFlags |= LOOPING;
1138 }
1139
1140 return OK;
1141}
1142
1143status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -07001144 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001145
1146 if (mDurationUs < 0) {
1147 return UNKNOWN_ERROR;
1148 }
1149
1150 *durationUs = mDurationUs;
1151
1152 return OK;
1153}
1154
1155status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -07001156 if (mRTSPController != NULL) {
1157 *positionUs = mRTSPController->getNormalPlayTimeUs();
1158 }
1159 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -07001160 *positionUs = mSeekTimeUs;
1161 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -07001162 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001163 *positionUs = mVideoTimeUs;
1164 } else if (mAudioPlayer != NULL) {
1165 *positionUs = mAudioPlayer->getMediaTimeUs();
1166 } else {
1167 *positionUs = 0;
1168 }
1169
1170 return OK;
1171}
1172
1173status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -07001174 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001175 Mutex::Autolock autoLock(mLock);
1176 return seekTo_l(timeUs);
1177 }
1178
1179 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -08001180}
1181
Andreas Huber0c46b692010-10-08 15:21:08 -07001182// static
1183void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
1184 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
1185}
1186
1187void AwesomePlayer::onRTSPSeekDone() {
1188 notifyListener_l(MEDIA_SEEK_COMPLETE);
1189 mSeekNotificationSent = true;
1190}
1191
Andreas Huber27366fc2009-11-20 09:32:46 -08001192status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001193 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -07001194 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -07001195 return OK;
1196 }
1197
Andreas Huber4d61f602010-06-10 11:17:50 -07001198 if (mFlags & CACHE_UNDERRUN) {
1199 mFlags &= ~CACHE_UNDERRUN;
1200 play_l();
1201 }
1202
Andreas Huber27366fc2009-11-20 09:32:46 -08001203 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001204 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001205 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001206 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -08001207
1208 seekAudioIfNecessary_l();
1209
Andreas Huber8e2b9412010-03-31 09:40:15 -07001210 if (!(mFlags & PLAYING)) {
1211 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1212 " immediately.");
1213
1214 notifyListener_l(MEDIA_SEEK_COMPLETE);
1215 mSeekNotificationSent = true;
1216 }
1217
Andreas Huber27366fc2009-11-20 09:32:46 -08001218 return OK;
1219}
1220
1221void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -08001222 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001223 mAudioPlayer->seekTo(mSeekTimeUs);
1224
Andreas Huber70d10c02010-02-03 11:37:29 -08001225 mWatchForAudioSeekComplete = true;
1226 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001227 mSeekNotificationSent = false;
Gloria Wangd5770912010-06-22 13:55:38 -07001228
1229 if (mDecryptHandle != NULL) {
1230 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1231 Playback::PAUSE, 0);
1232 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1233 Playback::START, mSeekTimeUs / 1000);
1234 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001235 }
1236}
1237
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001238void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1239 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001240
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001241 mAudioTrack = source;
1242}
1243
1244status_t AwesomePlayer::initAudioDecoder() {
1245 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -08001246
1247 const char *mime;
1248 CHECK(meta->findCString(kKeyMIMEType, &mime));
1249
1250 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001251 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -08001252 } else {
1253 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001254 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -08001255 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001256 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -08001257 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001258
1259 if (mAudioSource != NULL) {
1260 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001261 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001262 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001263 if (mDurationUs < 0 || durationUs > mDurationUs) {
1264 mDurationUs = durationUs;
1265 }
1266 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001267
Andreas Huber3c78a1b2010-05-13 09:15:21 -07001268 status_t err = mAudioSource->start();
1269
1270 if (err != OK) {
1271 mAudioSource.clear();
1272 return err;
1273 }
Andreas Huberd0332ad2010-04-12 16:05:57 -07001274 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1275 // For legacy reasons we're simply going to ignore the absence
1276 // of an audio decoder for QCELP instead of aborting playback
1277 // altogether.
1278 return OK;
1279 }
Andreas Huberdc9927d2010-03-08 15:46:13 -08001280
Andreas Huber27366fc2009-11-20 09:32:46 -08001281 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1282}
1283
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001284void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1285 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001286
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001287 mVideoTrack = source;
1288}
1289
Andreas Huber4c19bf92010-09-08 14:32:20 -07001290status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001291 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001292 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -08001293 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -07001294 mVideoTrack,
Andreas Huber6a1f5f92010-11-15 09:03:03 -08001295 NULL, flags, USE_SURFACE_ALLOC ? mSurface : NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001296
1297 if (mVideoSource != NULL) {
1298 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001299 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001300 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001301 if (mDurationUs < 0 || durationUs > mDurationUs) {
1302 mDurationUs = durationUs;
1303 }
1304 }
1305
Andreas Huber1919e5a2010-05-20 10:37:06 -07001306 status_t err = mVideoSource->start();
1307
1308 if (err != OK) {
1309 mVideoSource.clear();
1310 return err;
1311 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001312 }
1313
1314 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1315}
1316
Andreas Huber4d450a82010-10-19 09:34:44 -07001317void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1318 if (!mSeeking) {
1319 return;
1320 }
1321
1322 if (mAudioPlayer != NULL) {
Jamie Gennis6913c612010-10-20 15:55:43 -07001323 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
Andreas Huber4d450a82010-10-19 09:34:44 -07001324
1325 // If we don't have a video time, seek audio to the originally
1326 // requested seek time instead.
1327
1328 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1329 mAudioPlayer->resume();
1330 mWatchForAudioSeekComplete = true;
1331 mWatchForAudioEOS = true;
1332 } else if (!mSeekNotificationSent) {
1333 // If we're playing video only, report seek complete now,
1334 // otherwise audio player will notify us later.
1335 notifyListener_l(MEDIA_SEEK_COMPLETE);
1336 }
1337
1338 mFlags |= FIRST_FRAME;
1339 mSeeking = false;
1340 mSeekNotificationSent = false;
Gloria Wang3f9a8192010-10-29 14:50:17 -07001341
1342 if (mDecryptHandle != NULL) {
1343 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1344 Playback::PAUSE, 0);
1345 mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
1346 Playback::START, videoTimeUs / 1000);
1347 }
Andreas Huber4d450a82010-10-19 09:34:44 -07001348}
1349
Andreas Huber6be780e2010-02-08 14:40:30 -08001350void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001351 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001352 if (!mVideoEventPending) {
1353 // The event has been cancelled in reset_l() but had already
1354 // been scheduled for execution at that time.
1355 return;
1356 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001357 mVideoEventPending = false;
1358
1359 if (mSeeking) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001360 if (mVideoBuffer) {
1361 mVideoBuffer->release();
1362 mVideoBuffer = NULL;
1363 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001364
1365 if (mCachedSource != NULL && mAudioSource != NULL) {
1366 // We're going to seek the video source first, followed by
1367 // the audio source.
1368 // In order to avoid jumps in the DataSource offset caused by
1369 // the audio codec prefetching data from the old locations
1370 // while the video codec is already reading data from the new
1371 // locations, we'll "pause" the audio source, causing it to
1372 // stop reading input data until a subsequent seek.
1373
1374 if (mAudioPlayer != NULL) {
1375 mAudioPlayer->pause();
1376 }
1377 mAudioSource->pause();
1378 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001379 }
1380
1381 if (!mVideoBuffer) {
1382 MediaSource::ReadOptions options;
1383 if (mSeeking) {
1384 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1385
Andreas Huber6624c9f2010-07-20 15:04:28 -07001386 options.setSeekTo(
1387 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001388 }
1389 for (;;) {
1390 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001391 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001392
1393 if (err != OK) {
Andreas Huber52b52cd2010-11-23 11:41:34 -08001394 CHECK(mVideoBuffer == NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001395
1396 if (err == INFO_FORMAT_CHANGED) {
1397 LOGV("VideoSource signalled format change.");
1398
Andreas Hubere3c01832010-08-16 08:49:37 -07001399 notifyVideoSize_l();
1400
Andreas Huber7085b6842010-02-03 16:02:02 -08001401 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001402 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001403 initRenderer_l();
1404 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001405 continue;
1406 }
1407
Andreas Huber4d450a82010-10-19 09:34:44 -07001408 // So video playback is complete, but we may still have
1409 // a seek request pending that needs to be applied
1410 // to the audio track.
1411 if (mSeeking) {
1412 LOGV("video stream ended while seeking!");
1413 }
1414 finishSeekIfNecessary(-1);
1415
Andreas Huber971305d2010-07-07 13:35:27 -07001416 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001417 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001418 return;
1419 }
1420
Andreas Hubera67d5382009-12-10 15:32:12 -08001421 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001422 // Some decoders, notably the PV AVC software decoder
1423 // return spurious empty buffers that we just want to ignore.
1424
Andreas Hubera67d5382009-12-10 15:32:12 -08001425 mVideoBuffer->release();
1426 mVideoBuffer = NULL;
1427 continue;
1428 }
1429
Andreas Huber27366fc2009-11-20 09:32:46 -08001430 break;
1431 }
1432 }
1433
1434 int64_t timeUs;
1435 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1436
Andreas Huber252573c2010-03-26 10:17:17 -07001437 {
1438 Mutex::Autolock autoLock(mMiscStateLock);
1439 mVideoTimeUs = timeUs;
1440 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001441
Andreas Huber614d22c2010-10-29 15:47:52 -07001442 bool wasSeeking = mSeeking;
Andreas Huber4d450a82010-10-19 09:34:44 -07001443 finishSeekIfNecessary(timeUs);
Andreas Huber27366fc2009-11-20 09:32:46 -08001444
Andreas Huber971305d2010-07-07 13:35:27 -07001445 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1446
Andreas Huber27366fc2009-11-20 09:32:46 -08001447 if (mFlags & FIRST_FRAME) {
1448 mFlags &= ~FIRST_FRAME;
1449
Andreas Huber971305d2010-07-07 13:35:27 -07001450 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001451 }
1452
1453 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001454 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001455 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1456 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1457 }
1458
Andreas Huber971305d2010-07-07 13:35:27 -07001459 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001460
1461 int64_t latenessUs = nowUs - timeUs;
1462
Andreas Huber614d22c2010-10-29 15:47:52 -07001463 if (wasSeeking) {
1464 // Let's display the first frame after seeking right away.
1465 latenessUs = 0;
1466 }
1467
Andreas Huberf88f8442010-08-10 11:18:36 -07001468 if (mRTPSession != NULL) {
1469 // We'll completely ignore timestamps for gtalk videochat
1470 // and we'll play incoming video as fast as we get it.
1471 latenessUs = 0;
1472 }
1473
Andreas Huber24b0a952009-11-23 14:02:00 -08001474 if (latenessUs > 40000) {
1475 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001476 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001477
1478 mVideoBuffer->release();
1479 mVideoBuffer = NULL;
1480
1481 postVideoEvent_l();
1482 return;
1483 }
1484
1485 if (latenessUs < -10000) {
1486 // We're more than 10ms early.
1487
1488 postVideoEvent_l(10000);
1489 return;
1490 }
1491
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001492 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1493 mVideoRendererIsPreview = false;
1494
Andreas Huber7085b6842010-02-03 16:02:02 -08001495 initRenderer_l();
1496 }
1497
1498 if (mVideoRenderer != NULL) {
1499 mVideoRenderer->render(mVideoBuffer);
1500 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001501
Andreas Huber1bb0ffd2010-11-22 13:06:35 -08001502 mVideoBuffer->release();
Andreas Huber27366fc2009-11-20 09:32:46 -08001503 mVideoBuffer = NULL;
1504
1505 postVideoEvent_l();
1506}
1507
1508void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1509 if (mVideoEventPending) {
1510 return;
1511 }
1512
1513 mVideoEventPending = true;
1514 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1515}
1516
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001517void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001518 if (mStreamDoneEventPending) {
1519 return;
1520 }
1521 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001522
1523 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001524 mQueue.postEvent(mStreamDoneEvent);
1525}
1526
Andreas Huberb9e63832010-01-26 16:20:10 -08001527void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001528 if (mBufferingEventPending) {
1529 return;
1530 }
1531 mBufferingEventPending = true;
1532 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1533}
1534
Andreas Huber70d10c02010-02-03 11:37:29 -08001535void AwesomePlayer::postCheckAudioStatusEvent_l() {
1536 if (mAudioStatusEventPending) {
1537 return;
1538 }
1539 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001540 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001541}
1542
1543void AwesomePlayer::onCheckAudioStatus() {
1544 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001545 if (!mAudioStatusEventPending) {
1546 // Event was dispatched and while we were blocking on the mutex,
1547 // has already been cancelled.
1548 return;
1549 }
1550
Andreas Huber70d10c02010-02-03 11:37:29 -08001551 mAudioStatusEventPending = false;
1552
1553 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1554 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001555
1556 if (!mSeekNotificationSent) {
1557 notifyListener_l(MEDIA_SEEK_COMPLETE);
1558 mSeekNotificationSent = true;
1559 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001560
1561 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001562 }
1563
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001564 status_t finalStatus;
1565 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001566 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001567 mFlags |= AUDIO_AT_EOS;
1568 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001569 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001570 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001571}
1572
Andreas Huber6be780e2010-02-08 14:40:30 -08001573status_t AwesomePlayer::prepare() {
1574 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001575 return prepare_l();
1576}
Andreas Huber6be780e2010-02-08 14:40:30 -08001577
Andreas Huberffdf4782010-02-09 14:05:43 -08001578status_t AwesomePlayer::prepare_l() {
1579 if (mFlags & PREPARED) {
1580 return OK;
1581 }
1582
1583 if (mFlags & PREPARING) {
1584 return UNKNOWN_ERROR;
1585 }
1586
1587 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001588 status_t err = prepareAsync_l();
1589
1590 if (err != OK) {
1591 return err;
1592 }
1593
Andreas Huberffdf4782010-02-09 14:05:43 -08001594 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001595 mPreparedCondition.wait(mLock);
1596 }
1597
Andreas Huberffdf4782010-02-09 14:05:43 -08001598 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001599}
1600
1601status_t AwesomePlayer::prepareAsync() {
1602 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001603
1604 if (mFlags & PREPARING) {
1605 return UNKNOWN_ERROR; // async prepare already pending
1606 }
1607
1608 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001609 return prepareAsync_l();
1610}
1611
1612status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001613 if (mFlags & PREPARING) {
1614 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001615 }
1616
Andreas Huber406a18b2010-02-18 16:45:13 -08001617 if (!mQueueStarted) {
1618 mQueue.start();
1619 mQueueStarted = true;
1620 }
1621
Andreas Huberffdf4782010-02-09 14:05:43 -08001622 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001623 mAsyncPrepareEvent = new AwesomeEvent(
1624 this, &AwesomePlayer::onPrepareAsyncEvent);
1625
1626 mQueue.postEvent(mAsyncPrepareEvent);
1627
1628 return OK;
1629}
1630
Andreas Huberffdf4782010-02-09 14:05:43 -08001631status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001632 sp<DataSource> dataSource;
1633
1634 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001635 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001636
1637 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001638 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001639 mLock.lock();
1640
1641 if (err != OK) {
1642 mConnectingDataSource.clear();
1643
1644 LOGI("mConnectingDataSource->connect() returned %d", err);
1645 return err;
1646 }
1647
Andreas Huber4d61f602010-06-10 11:17:50 -07001648#if 0
1649 mCachedSource = new NuCachedSource2(
1650 new ThrottledSource(
1651 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1652#else
1653 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1654#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001655 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001656
1657 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001658 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1659 String8 uri("http://");
1660 uri.append(mUri.string() + 11);
1661
Andreas Huber54d09722010-10-12 11:34:37 -07001662 sp<LiveSource> liveSource = new LiveSource(uri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001663
Andreas Huber54d09722010-10-12 11:34:37 -07001664 mCachedSource = new NuCachedSource2(liveSource);
Andreas Huber4d61f602010-06-10 11:17:50 -07001665 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001666
1667 sp<MediaExtractor> extractor =
1668 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001669
Andreas Huber54d09722010-10-12 11:34:37 -07001670 static_cast<MPEG2TSExtractor *>(extractor.get())
1671 ->setLiveSource(liveSource);
1672
Andreas Huber4d61f602010-06-10 11:17:50 -07001673 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001674 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001675 if (mLooper == NULL) {
1676 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001677 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001678 mLooper->start(
1679 false /* runOnCallingThread */,
1680 false /* canCallJava */,
1681 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001682 }
1683
Mike Dodd8741dfa2010-08-12 16:04:35 -07001684 const char *startOfCodecString = &mUri.string()[13];
1685 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1686 if (startOfSlash1 == NULL) {
1687 return BAD_VALUE;
1688 }
1689 const char *startOfWidthString = &startOfSlash1[1];
1690 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1691 if (startOfSlash2 == NULL) {
1692 return BAD_VALUE;
1693 }
1694 const char *startOfHeightString = &startOfSlash2[1];
1695
1696 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1697 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1698 String8 heightString(startOfHeightString);
1699
Andreas Huber57648e42010-08-04 10:14:30 -07001700#if 0
1701 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1702 mLooper->registerHandler(mRTPPusher);
1703
1704 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1705 mLooper->registerHandler(mRTCPPusher);
1706#endif
1707
1708 mRTPSession = new ARTPSession;
1709 mLooper->registerHandler(mRTPSession);
1710
1711#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001712 // My AMR SDP
1713 static const char *raw =
1714 "v=0\r\n"
1715 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1716 "s=QuickTime\r\n"
1717 "t=0 0\r\n"
1718 "a=range:npt=0-315\r\n"
1719 "a=isma-compliance:2,2.0,2\r\n"
1720 "m=audio 5434 RTP/AVP 97\r\n"
1721 "c=IN IP4 127.0.0.1\r\n"
1722 "b=AS:30\r\n"
1723 "a=rtpmap:97 AMR/8000/1\r\n"
1724 "a=fmtp:97 octet-align\r\n";
1725#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001726 String8 sdp;
1727 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001728 "v=0\r\n"
1729 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1730 "s=QuickTime\r\n"
1731 "t=0 0\r\n"
1732 "a=range:npt=0-315\r\n"
1733 "a=isma-compliance:2,2.0,2\r\n"
1734 "m=video 5434 RTP/AVP 97\r\n"
1735 "c=IN IP4 127.0.0.1\r\n"
1736 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001737 "a=rtpmap:97 %s/90000\r\n"
1738 "a=cliprect:0,0,%s,%s\r\n"
1739 "a=framesize:97 %s-%s\r\n",
1740
1741 codecString.string(),
1742 heightString.string(), widthString.string(),
1743 widthString.string(), heightString.string()
1744 );
1745 const char *raw = sdp.string();
1746
Andreas Huber57648e42010-08-04 10:14:30 -07001747#endif
1748
1749 sp<ASessionDescription> desc = new ASessionDescription;
1750 CHECK(desc->setTo(raw, strlen(raw)));
1751
1752 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1753
1754 if (mRTPPusher != NULL) {
1755 mRTPPusher->start();
1756 }
1757
1758 if (mRTCPPusher != NULL) {
1759 mRTCPPusher->start();
1760 }
1761
1762 CHECK_EQ(mRTPSession->countTracks(), 1u);
1763 sp<MediaSource> source = mRTPSession->trackAt(0);
1764
1765#if 0
1766 bool eos;
1767 while (((APacketSource *)source.get())
1768 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1769 usleep(100000ll);
1770 }
1771#endif
1772
1773 const char *mime;
1774 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1775
1776 if (!strncasecmp("video/", mime, 6)) {
1777 setVideoSource(source);
1778 } else {
1779 CHECK(!strncasecmp("audio/", mime, 6));
1780 setAudioSource(source);
1781 }
1782
1783 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1784
1785 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001786 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1787 if (mLooper == NULL) {
1788 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001789 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001790 mLooper->start();
1791 }
1792 mRTSPController = new ARTSPController(mLooper);
1793 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001794
Andreas Huber7a747b82010-06-07 15:19:40 -07001795 LOGI("ARTSPController::connect returned %d", err);
1796
1797 if (err != OK) {
1798 mRTSPController.clear();
1799 return err;
1800 }
1801
1802 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001803 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001804 } else {
1805 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1806 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001807
1808 if (dataSource == NULL) {
1809 return UNKNOWN_ERROR;
1810 }
1811
1812 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1813
1814 if (extractor == NULL) {
1815 return UNKNOWN_ERROR;
1816 }
1817
Gloria Wangd5770912010-06-22 13:55:38 -07001818 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
Gloria Wangc2c22e72010-11-01 15:53:16 -07001819 if (mDecryptHandle != NULL) {
1820 if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) {
1821 if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) {
1822 LOGD("Setting mCachedSource to NULL for WVM\n");
1823 mCachedSource.clear();
1824 }
1825 } else {
1826 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
1827 }
Gloria Wangd5770912010-06-22 13:55:38 -07001828 }
1829
Andreas Huberffdf4782010-02-09 14:05:43 -08001830 return setDataSource_l(extractor);
1831}
1832
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001833void AwesomePlayer::abortPrepare(status_t err) {
1834 CHECK(err != OK);
1835
1836 if (mIsAsyncPrepare) {
1837 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1838 }
1839
1840 mPrepareResult = err;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001841 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001842 mAsyncPrepareEvent = NULL;
1843 mPreparedCondition.broadcast();
1844}
1845
Andreas Huberf71daba2010-03-24 09:24:40 -07001846// static
1847bool AwesomePlayer::ContinuePreparation(void *cookie) {
1848 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1849
1850 return (me->mFlags & PREPARE_CANCELLED) == 0;
1851}
1852
Andreas Huber6be780e2010-02-08 14:40:30 -08001853void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001854 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001855
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001856 if (mFlags & PREPARE_CANCELLED) {
1857 LOGI("prepare was cancelled before doing anything");
1858 abortPrepare(UNKNOWN_ERROR);
1859 return;
1860 }
1861
1862 if (mUri.size() > 0) {
1863 status_t err = finishSetDataSource_l();
1864
1865 if (err != OK) {
1866 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001867 return;
1868 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001869 }
1870
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001871 if (mVideoTrack != NULL && mVideoSource == NULL) {
1872 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001873
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001874 if (err != OK) {
1875 abortPrepare(err);
1876 return;
1877 }
1878 }
1879
1880 if (mAudioTrack != NULL && mAudioSource == NULL) {
1881 status_t err = initAudioDecoder();
1882
1883 if (err != OK) {
1884 abortPrepare(err);
1885 return;
1886 }
1887 }
1888
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001889 mFlags |= PREPARING_CONNECTED;
1890
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001891 if (mCachedSource != NULL || mRTSPController != NULL) {
1892 postBufferingEvent_l();
1893 } else {
1894 finishAsyncPrepare_l();
1895 }
1896}
1897
1898void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001899 if (mIsAsyncPrepare) {
Andreas Hubere3c01832010-08-16 08:49:37 -07001900 if (mVideoSource == NULL) {
Andreas Huberffdf4782010-02-09 14:05:43 -08001901 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1902 } else {
Andreas Hubere3c01832010-08-16 08:49:37 -07001903 notifyVideoSize_l();
Andreas Huberffdf4782010-02-09 14:05:43 -08001904 }
1905
1906 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001907 }
1908
Andreas Huberffdf4782010-02-09 14:05:43 -08001909 mPrepareResult = OK;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001910 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001911 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001912 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001913 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001914}
1915
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001916uint32_t AwesomePlayer::flags() const {
1917 return mExtractorFlags;
1918}
1919
Andreas Huber2b359ed2010-09-28 11:56:39 -07001920void AwesomePlayer::postAudioEOS() {
1921 postCheckAudioStatusEvent_l();
1922}
1923
1924void AwesomePlayer::postAudioSeekComplete() {
1925 postCheckAudioStatusEvent_l();
1926}
1927
Andreas Huber27366fc2009-11-20 09:32:46 -08001928} // namespace android