blob: a86ec7ff3a38bae1cdc1d87c0c9697f274004b4e [file] [log] [blame]
Andreas Huber27366fc2009-11-20 09:32:46 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "AwesomePlayer"
19#include <utils/Log.h>
20
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080021#include <dlfcn.h>
22
Andreas Huber7a747b82010-06-07 15:19:40 -070023#include "include/ARTSPController.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080024#include "include/AwesomePlayer.h"
Andreas Huber7a747b82010-06-07 15:19:40 -070025#include "include/LiveSource.h"
Andreas Huber1314e732009-12-14 14:18:22 -080026#include "include/SoftwareRenderer.h"
Andreas Huber4d61f602010-06-10 11:17:50 -070027#include "include/NuCachedSource2.h"
28#include "include/ThrottledSource.h"
Andreas Huber54d09722010-10-12 11:34:37 -070029#include "include/MPEG2TSExtractor.h"
Andreas Huber27366fc2009-11-20 09:32:46 -080030
Andreas Huber57648e42010-08-04 10:14:30 -070031#include "ARTPSession.h"
32#include "APacketSource.h"
33#include "ASessionDescription.h"
34#include "UDPPusher.h"
35
Andreas Hubera67d5382009-12-10 15:32:12 -080036#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080037#include <media/stagefright/AudioPlayer.h>
38#include <media/stagefright/DataSource.h>
39#include <media/stagefright/FileSource.h>
40#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080041#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080042#include <media/stagefright/MediaExtractor.h>
43#include <media/stagefright/MediaDebug.h>
44#include <media/stagefright/MediaSource.h>
45#include <media/stagefright/MetaData.h>
46#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080047
Andreas Hubere3c01832010-08-16 08:49:37 -070048#include <surfaceflinger/Surface.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080049
Andreas Huber7a747b82010-06-07 15:19:40 -070050#include <media/stagefright/foundation/ALooper.h>
Andreas Huber202348e2010-06-07 14:35:29 -070051
Andreas Huber27366fc2009-11-20 09:32:46 -080052namespace android {
53
Andreas Huber87ab9cd2010-09-03 13:20:33 -070054static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
55static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
56
Andreas Huber27366fc2009-11-20 09:32:46 -080057struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080058 AwesomeEvent(
59 AwesomePlayer *player,
60 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080061 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080062 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080063 }
64
65protected:
66 virtual ~AwesomeEvent() {}
67
68 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080069 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080070 }
71
72private:
73 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080074 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080075
76 AwesomeEvent(const AwesomeEvent &);
77 AwesomeEvent &operator=(const AwesomeEvent &);
78};
79
Andreas Huber1314e732009-12-14 14:18:22 -080080struct AwesomeRemoteRenderer : public AwesomeRenderer {
81 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
82 : mTarget(target) {
83 }
84
85 virtual void render(MediaBuffer *buffer) {
86 void *id;
87 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
88 mTarget->render((IOMX::buffer_id)id);
89 }
90 }
91
92private:
93 sp<IOMXRenderer> mTarget;
94
95 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
96 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
97};
98
99struct AwesomeLocalRenderer : public AwesomeRenderer {
100 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800101 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800102 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -0800103 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700104 const sp<ISurface> &isurface,
105 const sp<Surface> &surface,
Andreas Huber1314e732009-12-14 14:18:22 -0800106 size_t displayWidth, size_t displayHeight,
107 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800108 : mTarget(NULL),
109 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800110 init(previewOnly, componentName,
Andreas Hubere3c01832010-08-16 08:49:37 -0700111 colorFormat, isurface, surface, displayWidth,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800112 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800113 }
114
115 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800116 render((const uint8_t *)buffer->data() + buffer->range_offset(),
117 buffer->range_length());
118 }
119
120 void render(const void *data, size_t size) {
121 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800122 }
123
124protected:
125 virtual ~AwesomeLocalRenderer() {
126 delete mTarget;
127 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800128
129 if (mLibHandle) {
130 dlclose(mLibHandle);
131 mLibHandle = NULL;
132 }
Andreas Huber1314e732009-12-14 14:18:22 -0800133 }
134
135private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800136 VideoRenderer *mTarget;
137 void *mLibHandle;
138
139 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800140 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800141 const char *componentName,
142 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700143 const sp<ISurface> &isurface,
144 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800145 size_t displayWidth, size_t displayHeight,
146 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800147
148 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
149 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
150};
151
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800152void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800153 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800154 const char *componentName,
155 OMX_COLOR_FORMATTYPE colorFormat,
Andreas Hubere3c01832010-08-16 08:49:37 -0700156 const sp<ISurface> &isurface,
157 const sp<Surface> &surface,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800158 size_t displayWidth, size_t displayHeight,
159 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800160 if (!previewOnly) {
161 // We will stick to the vanilla software-color-converting renderer
162 // for "previewOnly" mode, to avoid unneccessarily switching overlays
163 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800164
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800165 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800166
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800167 if (mLibHandle) {
168 typedef VideoRenderer *(*CreateRendererFunc)(
169 const sp<ISurface> &surface,
170 const char *componentName,
171 OMX_COLOR_FORMATTYPE colorFormat,
172 size_t displayWidth, size_t displayHeight,
173 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800174
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800175 CreateRendererFunc func =
176 (CreateRendererFunc)dlsym(
177 mLibHandle,
178 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
179 "OMX_COLOR_FORMATTYPEjjjj");
180
181 if (func) {
182 mTarget =
Andreas Hubere3c01832010-08-16 08:49:37 -0700183 (*func)(isurface, componentName, colorFormat,
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800184 displayWidth, displayHeight,
185 decodedWidth, decodedHeight);
186 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800187 }
188 }
189
190 if (mTarget == NULL) {
191 mTarget = new SoftwareRenderer(
192 colorFormat, surface, displayWidth, displayHeight,
193 decodedWidth, decodedHeight);
194 }
195}
196
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700197struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
198 AwesomeNativeWindowRenderer(const sp<ANativeWindow> &nativeWindow)
199 : mNativeWindow(nativeWindow) {
200 }
201
202 virtual void render(MediaBuffer *buffer) {
203 status_t err = mNativeWindow->queueBuffer(
204 mNativeWindow.get(), buffer->graphicBuffer().get());
205 if (err != 0) {
206 LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
207 -err);
208 return;
209 }
210
211 sp<MetaData> metaData = buffer->meta_data();
212 metaData->setInt32(kKeyRendered, 1);
213 }
214
215protected:
216 virtual ~AwesomeNativeWindowRenderer() {}
217
218private:
219 sp<ANativeWindow> mNativeWindow;
220
221 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
222 AwesomeNativeWindowRenderer &operator=(
223 const AwesomeNativeWindowRenderer &);
224};
225
Andreas Huber27366fc2009-11-20 09:32:46 -0800226AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800227 : mQueueStarted(false),
228 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800229 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800230 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800231 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700232 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800233 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800234 mVideoBuffer(NULL),
235 mSuspensionState(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800236 CHECK_EQ(mClient.connect(), OK);
237
238 DataSource::RegisterDefaultSniffers();
239
Andreas Huber6be780e2010-02-08 14:40:30 -0800240 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800241 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800242 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800243 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800244 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800245 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800246
247 mCheckAudioStatusEvent = new AwesomeEvent(
248 this, &AwesomePlayer::onCheckAudioStatus);
249
Andreas Huber70d10c02010-02-03 11:37:29 -0800250 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800251
Andreas Huber27366fc2009-11-20 09:32:46 -0800252 reset();
253}
254
255AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800256 if (mQueueStarted) {
257 mQueue.stop();
258 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800259
260 reset();
261
262 mClient.disconnect();
263}
264
Andreas Huberb9e63832010-01-26 16:20:10 -0800265void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800266 mQueue.cancelEvent(mVideoEvent->eventID());
267 mVideoEventPending = false;
268 mQueue.cancelEvent(mStreamDoneEvent->eventID());
269 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800270 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
271 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800272
273 if (!keepBufferingGoing) {
274 mQueue.cancelEvent(mBufferingEvent->eventID());
275 mBufferingEventPending = false;
276 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800277}
278
Andreas Hubera3f43842010-01-21 10:28:45 -0800279void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800280 Mutex::Autolock autoLock(mLock);
281 mListener = listener;
282}
283
Andreas Huber433c9ac2010-01-27 16:49:05 -0800284status_t AwesomePlayer::setDataSource(
285 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800286 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800287 return setDataSource_l(uri, headers);
288}
Andreas Huber27366fc2009-11-20 09:32:46 -0800289
Andreas Huberba7ec912010-02-12 10:42:02 -0800290status_t AwesomePlayer::setDataSource_l(
291 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800292 reset_l();
293
Andreas Huberffdf4782010-02-09 14:05:43 -0800294 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800295
Andreas Huberffdf4782010-02-09 14:05:43 -0800296 if (headers) {
297 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800298 }
299
Andreas Huberffdf4782010-02-09 14:05:43 -0800300 // The actual work will be done during preparation in the call to
301 // ::finishSetDataSource_l to avoid blocking the calling thread in
302 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800303
Andreas Huberffdf4782010-02-09 14:05:43 -0800304 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800305}
306
307status_t AwesomePlayer::setDataSource(
308 int fd, int64_t offset, int64_t length) {
309 Mutex::Autolock autoLock(mLock);
310
311 reset_l();
312
Andreas Huberba7ec912010-02-12 10:42:02 -0800313 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800314
Andreas Huberba7ec912010-02-12 10:42:02 -0800315 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800316
317 if (err != OK) {
318 return err;
319 }
320
Andreas Huberba7ec912010-02-12 10:42:02 -0800321 mFileSource = dataSource;
322
323 return setDataSource_l(dataSource);
324}
325
326status_t AwesomePlayer::setDataSource_l(
327 const sp<DataSource> &dataSource) {
328 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800329
330 if (extractor == NULL) {
331 return UNKNOWN_ERROR;
332 }
333
334 return setDataSource_l(extractor);
335}
336
337status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700338 // Attempt to approximate overall stream bitrate by summing all
339 // tracks' individual bitrates, if not all of them advertise bitrate,
340 // we have to fail.
341
342 int64_t totalBitRate = 0;
343
344 for (size_t i = 0; i < extractor->countTracks(); ++i) {
345 sp<MetaData> meta = extractor->getTrackMetaData(i);
346
347 int32_t bitrate;
348 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
349 totalBitRate = -1;
350 break;
351 }
352
353 totalBitRate += bitrate;
354 }
355
356 mBitrate = totalBitRate;
357
358 LOGV("mBitrate = %lld bits/sec", mBitrate);
359
Andreas Huber27366fc2009-11-20 09:32:46 -0800360 bool haveAudio = false;
361 bool haveVideo = false;
362 for (size_t i = 0; i < extractor->countTracks(); ++i) {
363 sp<MetaData> meta = extractor->getTrackMetaData(i);
364
365 const char *mime;
366 CHECK(meta->findCString(kKeyMIMEType, &mime));
367
368 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800369 setVideoSource(extractor->getTrack(i));
370 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800371 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800372 setAudioSource(extractor->getTrack(i));
373 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700374
Andreas Huber1913c1a2010-10-04 11:09:31 -0700375 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
376 // Only do this for vorbis audio, none of the other audio
377 // formats even support this ringtone specific hack and
378 // retrieving the metadata on some extractors may turn out
379 // to be very expensive.
380 sp<MetaData> fileMeta = extractor->getMetaData();
381 int32_t loop;
382 if (fileMeta != NULL
383 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
384 mFlags |= AUTO_LOOPING;
385 }
Andreas Huber9fee0b22010-09-03 14:09:21 -0700386 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800387 }
388
389 if (haveAudio && haveVideo) {
390 break;
391 }
392 }
393
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700394 if (!haveAudio && !haveVideo) {
395 return UNKNOWN_ERROR;
396 }
397
398 mExtractorFlags = extractor->flags();
399
400 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800401}
402
403void AwesomePlayer::reset() {
404 Mutex::Autolock autoLock(mLock);
405 reset_l();
406}
407
408void AwesomePlayer::reset_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -0800409 if (mFlags & PREPARING) {
410 mFlags |= PREPARE_CANCELLED;
411 if (mConnectingDataSource != NULL) {
412 LOGI("interrupting the connection process");
413 mConnectingDataSource->disconnect();
414 }
Andreas Hubereaf2c5a2010-10-19 12:18:51 -0700415
416 if (mFlags & PREPARING_CONNECTED) {
417 // We are basically done preparing, we're just buffering
418 // enough data to start playback, we can safely interrupt that.
419 finishAsyncPrepare_l();
420 }
Andreas Huberedbb4d82010-03-12 08:59:22 -0800421 }
422
Andreas Huberffdf4782010-02-09 14:05:43 -0800423 while (mFlags & PREPARING) {
424 mPreparedCondition.wait(mLock);
425 }
426
Andreas Huber27366fc2009-11-20 09:32:46 -0800427 cancelPlayerEvents();
428
Andreas Huber4d61f602010-06-10 11:17:50 -0700429 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800430 mAudioTrack.clear();
431 mVideoTrack.clear();
432
Andreas Huberba7ec912010-02-12 10:42:02 -0800433 // Shutdown audio first, so that the respone to the reset request
434 // appears to happen instantaneously as far as the user is concerned
435 // If we did this later, audio would continue playing while we
436 // shutdown the video-related resources and the player appear to
437 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800438 if (mAudioPlayer == NULL && mAudioSource != NULL) {
439 // If we had an audio player, it would have effectively
440 // taken possession of the audio source and stopped it when
441 // _it_ is stopped. Otherwise this is still our responsibility.
442 mAudioSource->stop();
443 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800444 mAudioSource.clear();
445
Andreas Huberba7ec912010-02-12 10:42:02 -0800446 mTimeSource = NULL;
447
448 delete mAudioPlayer;
449 mAudioPlayer = NULL;
450
Andreas Huber3522b5a52010-01-22 14:36:53 -0800451 mVideoRenderer.clear();
452
Andreas Huber27366fc2009-11-20 09:32:46 -0800453 if (mLastVideoBuffer) {
454 mLastVideoBuffer->release();
455 mLastVideoBuffer = NULL;
456 }
457
458 if (mVideoBuffer) {
459 mVideoBuffer->release();
460 mVideoBuffer = NULL;
461 }
462
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700463 if (mRTSPController != NULL) {
464 mRTSPController->disconnect();
465 mRTSPController.clear();
466 }
467
Andreas Huber57648e42010-08-04 10:14:30 -0700468 mRTPPusher.clear();
469 mRTCPPusher.clear();
470 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700471
Andreas Huber27366fc2009-11-20 09:32:46 -0800472 if (mVideoSource != NULL) {
473 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800474
475 // The following hack is necessary to ensure that the OMX
476 // component is completely released by the time we may try
477 // to instantiate it again.
478 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800479 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800480 while (tmp.promote() != NULL) {
481 usleep(1000);
482 }
483 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800484 }
485
Andreas Huber27366fc2009-11-20 09:32:46 -0800486 mDurationUs = -1;
487 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700488 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800489 mVideoWidth = mVideoHeight = -1;
490 mTimeSourceDeltaUs = 0;
491 mVideoTimeUs = 0;
492
493 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700494 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800495 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800496
Andreas Huberffdf4782010-02-09 14:05:43 -0800497 mUri.setTo("");
498 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800499
500 mFileSource.clear();
501
502 delete mSuspensionState;
503 mSuspensionState = NULL;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700504
505 mBitrate = -1;
Andreas Huber27366fc2009-11-20 09:32:46 -0800506}
507
Andreas Huber6be780e2010-02-08 14:40:30 -0800508void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800509 if (mListener != NULL) {
510 sp<MediaPlayerBase> listener = mListener.promote();
511
512 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800513 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800514 }
515 }
516}
517
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700518bool AwesomePlayer::getBitrate(int64_t *bitrate) {
519 off_t size;
520 if (mDurationUs >= 0 && mCachedSource != NULL
521 && mCachedSource->getSize(&size) == OK) {
522 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
523 return true;
524 }
525
526 if (mBitrate >= 0) {
527 *bitrate = mBitrate;
528 return true;
529 }
530
531 *bitrate = 0;
532
533 return false;
534}
535
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700536// Returns true iff cached duration is available/applicable.
537bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700538 int64_t bitrate;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700539
540 if (mRTSPController != NULL) {
541 *durationUs = mRTSPController->getQueueDurationUs(eos);
542 return true;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700543 } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700544 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
545 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
546 return true;
547 }
548
549 return false;
550}
551
Andreas Huberb9e63832010-01-26 16:20:10 -0800552void AwesomePlayer::onBufferingUpdate() {
553 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800554 if (!mBufferingEventPending) {
555 return;
556 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800557 mBufferingEventPending = false;
558
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700559 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700560 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700561 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700562
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700563 if (eos) {
564 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700565 if (mFlags & PREPARING) {
566 LOGV("cache has reached EOS, prepare is done.");
567 finishAsyncPrepare_l();
568 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700569 } else {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700570 int64_t bitrate;
571 if (getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700572 size_t cachedSize = mCachedSource->cachedSize();
573 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
574
575 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
576 if (percentage > 100) {
577 percentage = 100;
578 }
579
580 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
581 } else {
582 // We don't know the bitrate of the stream, use absolute size
583 // limits to maintain the cache.
584
Andreas Huber54d09722010-10-12 11:34:37 -0700585 const size_t kLowWaterMarkBytes = 40000;
586 const size_t kHighWaterMarkBytes = 200000;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700587
588 if ((mFlags & PLAYING) && !eos
589 && (cachedDataRemaining < kLowWaterMarkBytes)) {
590 LOGI("cache is running low (< %d) , pausing.",
591 kLowWaterMarkBytes);
592 mFlags |= CACHE_UNDERRUN;
593 pause_l();
594 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
595 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
596 if (mFlags & CACHE_UNDERRUN) {
597 LOGI("cache has filled up (> %d), resuming.",
598 kHighWaterMarkBytes);
599 mFlags &= ~CACHE_UNDERRUN;
600 play_l();
601 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
602 } else if (mFlags & PREPARING) {
603 LOGV("cache has filled up (> %d), prepare is done",
604 kHighWaterMarkBytes);
605 finishAsyncPrepare_l();
606 }
607 }
608 }
609 }
610 }
611
612 int64_t cachedDurationUs;
613 bool eos;
614 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700615 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700616 && (cachedDurationUs < kLowWaterMarkUs)) {
617 LOGI("cache is running low (%.2f secs) , pausing.",
618 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700619 mFlags |= CACHE_UNDERRUN;
620 pause_l();
621 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700622 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
623 if (mFlags & CACHE_UNDERRUN) {
624 LOGI("cache has filled up (%.2f secs), resuming.",
625 cachedDurationUs / 1E6);
626 mFlags &= ~CACHE_UNDERRUN;
627 play_l();
628 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
629 } else if (mFlags & PREPARING) {
630 LOGV("cache has filled up (%.2f secs), prepare is done",
631 cachedDurationUs / 1E6);
632 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700633 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700634 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800635 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700636
Andreas Huber4d61f602010-06-10 11:17:50 -0700637 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800638}
639
Andreas Huber4c19bf92010-09-08 14:32:20 -0700640void AwesomePlayer::partial_reset_l() {
641 // Only reset the video renderer and shut down the video decoder.
642 // Then instantiate a new video decoder and resume video playback.
643
644 mVideoRenderer.clear();
645
646 if (mLastVideoBuffer) {
647 mLastVideoBuffer->release();
648 mLastVideoBuffer = NULL;
649 }
650
651 if (mVideoBuffer) {
652 mVideoBuffer->release();
653 mVideoBuffer = NULL;
654 }
655
656 {
657 mVideoSource->stop();
658
659 // The following hack is necessary to ensure that the OMX
660 // component is completely released by the time we may try
661 // to instantiate it again.
662 wp<MediaSource> tmp = mVideoSource;
663 mVideoSource.clear();
664 while (tmp.promote() != NULL) {
665 usleep(1000);
666 }
667 IPCThreadState::self()->flushCommands();
668 }
669
670 CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
671}
672
Andreas Huber27366fc2009-11-20 09:32:46 -0800673void AwesomePlayer::onStreamDone() {
674 // Posted whenever any stream finishes playing.
675
676 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800677 if (!mStreamDoneEventPending) {
678 return;
679 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800680 mStreamDoneEventPending = false;
681
Andreas Huber4c19bf92010-09-08 14:32:20 -0700682 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
683 // This special status is returned because an http live stream's
684 // video stream switched to a different bandwidth at this point
685 // and future data may have been encoded using different parameters.
686 // This requires us to shutdown the video decoder and reinstantiate
687 // a fresh one.
688
689 LOGV("INFO_DISCONTINUITY");
690
691 CHECK(mVideoSource != NULL);
692
693 partial_reset_l();
694 postVideoEvent_l();
695 return;
696 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700697 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
698
699 notifyListener_l(
700 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
701
Andreas Huberc743f452010-10-05 10:25:34 -0700702 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700703
704 mFlags |= AT_EOS;
705 return;
706 }
707
708 const bool allDone =
709 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
710 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
711
712 if (!allDone) {
713 return;
714 }
715
Andreas Huber9fee0b22010-09-03 14:09:21 -0700716 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800717 seekTo_l(0);
718
Andreas Huber7085b6842010-02-03 16:02:02 -0800719 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800720 postVideoEvent_l();
721 }
722 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700723 LOGV("MEDIA_PLAYBACK_COMPLETE");
724 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800725
Andreas Huberc743f452010-10-05 10:25:34 -0700726 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800727
728 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800729 }
730}
731
732status_t AwesomePlayer::play() {
733 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700734
735 mFlags &= ~CACHE_UNDERRUN;
736
Andreas Huberba7ec912010-02-12 10:42:02 -0800737 return play_l();
738}
Andreas Huber27366fc2009-11-20 09:32:46 -0800739
Andreas Huberba7ec912010-02-12 10:42:02 -0800740status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800741 if (mFlags & PLAYING) {
742 return OK;
743 }
744
Andreas Huberffdf4782010-02-09 14:05:43 -0800745 if (!(mFlags & PREPARED)) {
746 status_t err = prepare_l();
747
748 if (err != OK) {
749 return err;
750 }
751 }
752
Andreas Huber27366fc2009-11-20 09:32:46 -0800753 mFlags |= PLAYING;
754 mFlags |= FIRST_FRAME;
755
Andreas Huberc1d5c922009-12-10 15:49:04 -0800756 bool deferredAudioSeek = false;
757
Andreas Huber27366fc2009-11-20 09:32:46 -0800758 if (mAudioSource != NULL) {
759 if (mAudioPlayer == NULL) {
760 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700761 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800762 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800763
764 // We've already started the MediaSource in order to enable
765 // the prefetcher to read its data.
766 status_t err = mAudioPlayer->start(
767 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800768
769 if (err != OK) {
770 delete mAudioPlayer;
771 mAudioPlayer = NULL;
772
773 mFlags &= ~(PLAYING | FIRST_FRAME);
774
775 return err;
776 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800777
Andreas Huber27366fc2009-11-20 09:32:46 -0800778 mTimeSource = mAudioPlayer;
779
Andreas Huberc1d5c922009-12-10 15:49:04 -0800780 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800781
782 mWatchForAudioSeekComplete = false;
783 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800784 }
785 } else {
786 mAudioPlayer->resume();
787 }
788 }
789
790 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700791 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800792 }
793
794 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800795 // Kick off video playback
796 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800797 }
798
Andreas Huberc1d5c922009-12-10 15:49:04 -0800799 if (deferredAudioSeek) {
800 // If there was a seek request while we were paused
801 // and we're just starting up again, honor the request now.
802 seekAudioIfNecessary_l();
803 }
804
Andreas Huber406a18b2010-02-18 16:45:13 -0800805 if (mFlags & AT_EOS) {
806 // Legacy behaviour, if a stream finishes playing and then
807 // is started again, we play from the start...
808 seekTo_l(0);
809 }
810
Andreas Huber27366fc2009-11-20 09:32:46 -0800811 return OK;
812}
813
Andreas Hubere3c01832010-08-16 08:49:37 -0700814void AwesomePlayer::notifyVideoSize_l() {
815 sp<MetaData> meta = mVideoSource->getFormat();
816
817 int32_t decodedWidth, decodedHeight;
818 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
819 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
820
821 notifyListener_l(MEDIA_SET_VIDEO_SIZE, decodedWidth, decodedHeight);
822}
823
Andreas Huber27366fc2009-11-20 09:32:46 -0800824void AwesomePlayer::initRenderer_l() {
Andreas Hubere3c01832010-08-16 08:49:37 -0700825 if (mSurface != NULL || mISurface != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800826 sp<MetaData> meta = mVideoSource->getFormat();
827
828 int32_t format;
829 const char *component;
830 int32_t decodedWidth, decodedHeight;
831 CHECK(meta->findInt32(kKeyColorFormat, &format));
832 CHECK(meta->findCString(kKeyDecoderComponent, &component));
833 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
834 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
835
Andreas Hubera67d5382009-12-10 15:32:12 -0800836 mVideoRenderer.clear();
837
838 // Must ensure that mVideoRenderer's destructor is actually executed
839 // before creating a new one.
840 IPCThreadState::self()->flushCommands();
841
Andreas Hubere3c01832010-08-16 08:49:37 -0700842 if (mSurface != NULL) {
Jamie Gennis58a36ad2010-10-07 14:08:38 -0700843 if (strncmp(component, "OMX.", 4) == 0) {
844 // Hardware decoders avoid the CPU color conversion by decoding
845 // directly to ANativeBuffers, so we must use a renderer that
846 // just pushes those buffers to the ANativeWindow.
847 mVideoRenderer = new AwesomeNativeWindowRenderer(mSurface);
848 } else {
849 // Other decoders are instantiated locally and as a consequence
850 // allocate their buffers in local address space. This renderer
851 // then performs a color conversion and copy to get the data
852 // into the ANativeBuffer.
853 mVideoRenderer = new AwesomeLocalRenderer(
854 false, // previewOnly
855 component,
856 (OMX_COLOR_FORMATTYPE)format,
857 mISurface,
858 mSurface,
859 mVideoWidth, mVideoHeight,
860 decodedWidth, decodedHeight);
861 }
Andreas Hubere3c01832010-08-16 08:49:37 -0700862 } else {
Andreas Huber1314e732009-12-14 14:18:22 -0800863 // Our OMX codecs allocate buffers on the media_server side
864 // therefore they require a remote IOMXRenderer that knows how
865 // to display them.
866 mVideoRenderer = new AwesomeRemoteRenderer(
867 mClient.interface()->createRenderer(
868 mISurface, component,
869 (OMX_COLOR_FORMATTYPE)format,
870 decodedWidth, decodedHeight,
871 mVideoWidth, mVideoHeight));
Andreas Huber1314e732009-12-14 14:18:22 -0800872 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800873 }
874}
875
876status_t AwesomePlayer::pause() {
877 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700878
879 mFlags &= ~CACHE_UNDERRUN;
880
Andreas Huber27366fc2009-11-20 09:32:46 -0800881 return pause_l();
882}
883
Andreas Huberc743f452010-10-05 10:25:34 -0700884status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800885 if (!(mFlags & PLAYING)) {
886 return OK;
887 }
888
Andreas Huberb9e63832010-01-26 16:20:10 -0800889 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800890
891 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -0700892 if (at_eos) {
893 // If we played the audio stream to completion we
894 // want to make sure that all samples remaining in the audio
895 // track's queue are played out.
896 mAudioPlayer->pause(true /* playPendingSamples */);
897 } else {
898 mAudioPlayer->pause();
899 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800900 }
901
902 mFlags &= ~PLAYING;
903
904 return OK;
905}
906
907bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700908 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800909}
910
911void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
912 Mutex::Autolock autoLock(mLock);
913
914 mISurface = isurface;
915}
916
Andreas Hubere3c01832010-08-16 08:49:37 -0700917void AwesomePlayer::setSurface(const sp<Surface> &surface) {
918 Mutex::Autolock autoLock(mLock);
919
920 mSurface = surface;
921}
922
Andreas Huber27366fc2009-11-20 09:32:46 -0800923void AwesomePlayer::setAudioSink(
924 const sp<MediaPlayerBase::AudioSink> &audioSink) {
925 Mutex::Autolock autoLock(mLock);
926
927 mAudioSink = audioSink;
928}
929
930status_t AwesomePlayer::setLooping(bool shouldLoop) {
931 Mutex::Autolock autoLock(mLock);
932
933 mFlags = mFlags & ~LOOPING;
934
935 if (shouldLoop) {
936 mFlags |= LOOPING;
937 }
938
939 return OK;
940}
941
942status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700943 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800944
945 if (mDurationUs < 0) {
946 return UNKNOWN_ERROR;
947 }
948
949 *durationUs = mDurationUs;
950
951 return OK;
952}
953
954status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -0700955 if (mRTSPController != NULL) {
956 *positionUs = mRTSPController->getNormalPlayTimeUs();
957 }
958 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700959 *positionUs = mSeekTimeUs;
960 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700961 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800962 *positionUs = mVideoTimeUs;
963 } else if (mAudioPlayer != NULL) {
964 *positionUs = mAudioPlayer->getMediaTimeUs();
965 } else {
966 *positionUs = 0;
967 }
968
969 return OK;
970}
971
972status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -0700973 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700974 Mutex::Autolock autoLock(mLock);
975 return seekTo_l(timeUs);
976 }
977
978 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800979}
980
Andreas Huber0c46b692010-10-08 15:21:08 -0700981// static
982void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
983 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
984}
985
986void AwesomePlayer::onRTSPSeekDone() {
987 notifyListener_l(MEDIA_SEEK_COMPLETE);
988 mSeekNotificationSent = true;
989}
990
Andreas Huber27366fc2009-11-20 09:32:46 -0800991status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700992 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -0700993 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700994 return OK;
995 }
996
Andreas Huber4d61f602010-06-10 11:17:50 -0700997 if (mFlags & CACHE_UNDERRUN) {
998 mFlags &= ~CACHE_UNDERRUN;
999 play_l();
1000 }
1001
Andreas Huber27366fc2009-11-20 09:32:46 -08001002 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001003 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001004 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001005 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -08001006
1007 seekAudioIfNecessary_l();
1008
Andreas Huber8e2b9412010-03-31 09:40:15 -07001009 if (!(mFlags & PLAYING)) {
1010 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
1011 " immediately.");
1012
1013 notifyListener_l(MEDIA_SEEK_COMPLETE);
1014 mSeekNotificationSent = true;
1015 }
1016
Andreas Huber27366fc2009-11-20 09:32:46 -08001017 return OK;
1018}
1019
1020void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -08001021 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001022 mAudioPlayer->seekTo(mSeekTimeUs);
1023
Andreas Huber70d10c02010-02-03 11:37:29 -08001024 mWatchForAudioSeekComplete = true;
1025 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001026 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001027 }
1028}
1029
1030status_t AwesomePlayer::getVideoDimensions(
1031 int32_t *width, int32_t *height) const {
1032 Mutex::Autolock autoLock(mLock);
1033
1034 if (mVideoWidth < 0 || mVideoHeight < 0) {
1035 return UNKNOWN_ERROR;
1036 }
1037
1038 *width = mVideoWidth;
1039 *height = mVideoHeight;
1040
1041 return OK;
1042}
1043
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001044void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
1045 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001046
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001047 mAudioTrack = source;
1048}
1049
1050status_t AwesomePlayer::initAudioDecoder() {
1051 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -08001052
1053 const char *mime;
1054 CHECK(meta->findCString(kKeyMIMEType, &mime));
1055
1056 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001057 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -08001058 } else {
1059 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001060 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -08001061 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001062 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -08001063 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001064
1065 if (mAudioSource != NULL) {
1066 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001067 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001068 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001069 if (mDurationUs < 0 || durationUs > mDurationUs) {
1070 mDurationUs = durationUs;
1071 }
1072 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001073
Andreas Huber3c78a1b2010-05-13 09:15:21 -07001074 status_t err = mAudioSource->start();
1075
1076 if (err != OK) {
1077 mAudioSource.clear();
1078 return err;
1079 }
Andreas Huberd0332ad2010-04-12 16:05:57 -07001080 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1081 // For legacy reasons we're simply going to ignore the absence
1082 // of an audio decoder for QCELP instead of aborting playback
1083 // altogether.
1084 return OK;
1085 }
Andreas Huberdc9927d2010-03-08 15:46:13 -08001086
Andreas Huber27366fc2009-11-20 09:32:46 -08001087 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1088}
1089
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001090void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1091 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001092
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001093 mVideoTrack = source;
1094}
1095
Andreas Huber4c19bf92010-09-08 14:32:20 -07001096status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001097 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001098 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -08001099 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -07001100 mVideoTrack,
Jamie Gennis58a36ad2010-10-07 14:08:38 -07001101 NULL, flags, mSurface);
Andreas Huber27366fc2009-11-20 09:32:46 -08001102
1103 if (mVideoSource != NULL) {
1104 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001105 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001106 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001107 if (mDurationUs < 0 || durationUs > mDurationUs) {
1108 mDurationUs = durationUs;
1109 }
1110 }
1111
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001112 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
1113 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -08001114
Andreas Huber1919e5a2010-05-20 10:37:06 -07001115 status_t err = mVideoSource->start();
1116
1117 if (err != OK) {
1118 mVideoSource.clear();
1119 return err;
1120 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001121 }
1122
1123 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1124}
1125
Andreas Huber4d450a82010-10-19 09:34:44 -07001126void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
1127 if (!mSeeking) {
1128 return;
1129 }
1130
1131 if (mAudioPlayer != NULL) {
1132 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
1133
1134 // If we don't have a video time, seek audio to the originally
1135 // requested seek time instead.
1136
1137 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
1138 mAudioPlayer->resume();
1139 mWatchForAudioSeekComplete = true;
1140 mWatchForAudioEOS = true;
1141 } else if (!mSeekNotificationSent) {
1142 // If we're playing video only, report seek complete now,
1143 // otherwise audio player will notify us later.
1144 notifyListener_l(MEDIA_SEEK_COMPLETE);
1145 }
1146
1147 mFlags |= FIRST_FRAME;
1148 mSeeking = false;
1149 mSeekNotificationSent = false;
1150}
1151
Andreas Huber6be780e2010-02-08 14:40:30 -08001152void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001153 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001154 if (!mVideoEventPending) {
1155 // The event has been cancelled in reset_l() but had already
1156 // been scheduled for execution at that time.
1157 return;
1158 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001159 mVideoEventPending = false;
1160
1161 if (mSeeking) {
1162 if (mLastVideoBuffer) {
1163 mLastVideoBuffer->release();
1164 mLastVideoBuffer = NULL;
1165 }
1166
1167 if (mVideoBuffer) {
1168 mVideoBuffer->release();
1169 mVideoBuffer = NULL;
1170 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001171
1172 if (mCachedSource != NULL && mAudioSource != NULL) {
1173 // We're going to seek the video source first, followed by
1174 // the audio source.
1175 // In order to avoid jumps in the DataSource offset caused by
1176 // the audio codec prefetching data from the old locations
1177 // while the video codec is already reading data from the new
1178 // locations, we'll "pause" the audio source, causing it to
1179 // stop reading input data until a subsequent seek.
1180
1181 if (mAudioPlayer != NULL) {
1182 mAudioPlayer->pause();
1183 }
1184 mAudioSource->pause();
1185 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001186 }
1187
1188 if (!mVideoBuffer) {
1189 MediaSource::ReadOptions options;
1190 if (mSeeking) {
1191 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1192
Andreas Huber6624c9f2010-07-20 15:04:28 -07001193 options.setSeekTo(
1194 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001195 }
1196 for (;;) {
1197 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001198 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001199
1200 if (err != OK) {
1201 CHECK_EQ(mVideoBuffer, NULL);
1202
1203 if (err == INFO_FORMAT_CHANGED) {
1204 LOGV("VideoSource signalled format change.");
1205
Andreas Hubere3c01832010-08-16 08:49:37 -07001206 notifyVideoSize_l();
1207
Andreas Huber7085b6842010-02-03 16:02:02 -08001208 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001209 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001210 initRenderer_l();
1211 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001212 continue;
1213 }
1214
Andreas Huber4d450a82010-10-19 09:34:44 -07001215 // So video playback is complete, but we may still have
1216 // a seek request pending that needs to be applied
1217 // to the audio track.
1218 if (mSeeking) {
1219 LOGV("video stream ended while seeking!");
1220 }
1221 finishSeekIfNecessary(-1);
1222
Andreas Huber971305d2010-07-07 13:35:27 -07001223 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001224 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001225 return;
1226 }
1227
Andreas Hubera67d5382009-12-10 15:32:12 -08001228 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001229 // Some decoders, notably the PV AVC software decoder
1230 // return spurious empty buffers that we just want to ignore.
1231
Andreas Hubera67d5382009-12-10 15:32:12 -08001232 mVideoBuffer->release();
1233 mVideoBuffer = NULL;
1234 continue;
1235 }
1236
Andreas Huber27366fc2009-11-20 09:32:46 -08001237 break;
1238 }
1239 }
1240
1241 int64_t timeUs;
1242 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1243
Andreas Huber252573c2010-03-26 10:17:17 -07001244 {
1245 Mutex::Autolock autoLock(mMiscStateLock);
1246 mVideoTimeUs = timeUs;
1247 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001248
Andreas Huber4d450a82010-10-19 09:34:44 -07001249 finishSeekIfNecessary(timeUs);
Andreas Huber27366fc2009-11-20 09:32:46 -08001250
Andreas Huber971305d2010-07-07 13:35:27 -07001251 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1252
Andreas Huber27366fc2009-11-20 09:32:46 -08001253 if (mFlags & FIRST_FRAME) {
1254 mFlags &= ~FIRST_FRAME;
1255
Andreas Huber971305d2010-07-07 13:35:27 -07001256 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001257 }
1258
1259 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001260 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001261 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1262 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1263 }
1264
Andreas Huber971305d2010-07-07 13:35:27 -07001265 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001266
1267 int64_t latenessUs = nowUs - timeUs;
1268
Andreas Huberf88f8442010-08-10 11:18:36 -07001269 if (mRTPSession != NULL) {
1270 // We'll completely ignore timestamps for gtalk videochat
1271 // and we'll play incoming video as fast as we get it.
1272 latenessUs = 0;
1273 }
1274
Andreas Huber24b0a952009-11-23 14:02:00 -08001275 if (latenessUs > 40000) {
1276 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001277 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001278
1279 mVideoBuffer->release();
1280 mVideoBuffer = NULL;
1281
1282 postVideoEvent_l();
1283 return;
1284 }
1285
1286 if (latenessUs < -10000) {
1287 // We're more than 10ms early.
1288
1289 postVideoEvent_l(10000);
1290 return;
1291 }
1292
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001293 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1294 mVideoRendererIsPreview = false;
1295
Andreas Huber7085b6842010-02-03 16:02:02 -08001296 initRenderer_l();
1297 }
1298
1299 if (mVideoRenderer != NULL) {
1300 mVideoRenderer->render(mVideoBuffer);
1301 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001302
1303 if (mLastVideoBuffer) {
1304 mLastVideoBuffer->release();
1305 mLastVideoBuffer = NULL;
1306 }
1307 mLastVideoBuffer = mVideoBuffer;
1308 mVideoBuffer = NULL;
1309
1310 postVideoEvent_l();
1311}
1312
1313void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1314 if (mVideoEventPending) {
1315 return;
1316 }
1317
1318 mVideoEventPending = true;
1319 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1320}
1321
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001322void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001323 if (mStreamDoneEventPending) {
1324 return;
1325 }
1326 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001327
1328 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001329 mQueue.postEvent(mStreamDoneEvent);
1330}
1331
Andreas Huberb9e63832010-01-26 16:20:10 -08001332void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001333 if (mBufferingEventPending) {
1334 return;
1335 }
1336 mBufferingEventPending = true;
1337 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1338}
1339
Andreas Huber70d10c02010-02-03 11:37:29 -08001340void AwesomePlayer::postCheckAudioStatusEvent_l() {
1341 if (mAudioStatusEventPending) {
1342 return;
1343 }
1344 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001345 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001346}
1347
1348void AwesomePlayer::onCheckAudioStatus() {
1349 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001350 if (!mAudioStatusEventPending) {
1351 // Event was dispatched and while we were blocking on the mutex,
1352 // has already been cancelled.
1353 return;
1354 }
1355
Andreas Huber70d10c02010-02-03 11:37:29 -08001356 mAudioStatusEventPending = false;
1357
1358 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1359 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001360
1361 if (!mSeekNotificationSent) {
1362 notifyListener_l(MEDIA_SEEK_COMPLETE);
1363 mSeekNotificationSent = true;
1364 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001365
1366 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001367 }
1368
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001369 status_t finalStatus;
1370 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001371 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001372 mFlags |= AUDIO_AT_EOS;
1373 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001374 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001375 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001376}
1377
Andreas Huber6be780e2010-02-08 14:40:30 -08001378status_t AwesomePlayer::prepare() {
1379 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001380 return prepare_l();
1381}
Andreas Huber6be780e2010-02-08 14:40:30 -08001382
Andreas Huberffdf4782010-02-09 14:05:43 -08001383status_t AwesomePlayer::prepare_l() {
1384 if (mFlags & PREPARED) {
1385 return OK;
1386 }
1387
1388 if (mFlags & PREPARING) {
1389 return UNKNOWN_ERROR;
1390 }
1391
1392 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001393 status_t err = prepareAsync_l();
1394
1395 if (err != OK) {
1396 return err;
1397 }
1398
Andreas Huberffdf4782010-02-09 14:05:43 -08001399 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001400 mPreparedCondition.wait(mLock);
1401 }
1402
Andreas Huberffdf4782010-02-09 14:05:43 -08001403 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001404}
1405
1406status_t AwesomePlayer::prepareAsync() {
1407 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001408
1409 if (mFlags & PREPARING) {
1410 return UNKNOWN_ERROR; // async prepare already pending
1411 }
1412
1413 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001414 return prepareAsync_l();
1415}
1416
1417status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001418 if (mFlags & PREPARING) {
1419 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001420 }
1421
Andreas Huber406a18b2010-02-18 16:45:13 -08001422 if (!mQueueStarted) {
1423 mQueue.start();
1424 mQueueStarted = true;
1425 }
1426
Andreas Huberffdf4782010-02-09 14:05:43 -08001427 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001428 mAsyncPrepareEvent = new AwesomeEvent(
1429 this, &AwesomePlayer::onPrepareAsyncEvent);
1430
1431 mQueue.postEvent(mAsyncPrepareEvent);
1432
1433 return OK;
1434}
1435
Andreas Huberffdf4782010-02-09 14:05:43 -08001436status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001437 sp<DataSource> dataSource;
1438
1439 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001440 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001441
1442 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001443 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001444 mLock.lock();
1445
1446 if (err != OK) {
1447 mConnectingDataSource.clear();
1448
1449 LOGI("mConnectingDataSource->connect() returned %d", err);
1450 return err;
1451 }
1452
Andreas Huber4d61f602010-06-10 11:17:50 -07001453#if 0
1454 mCachedSource = new NuCachedSource2(
1455 new ThrottledSource(
1456 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1457#else
1458 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1459#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001460 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001461
1462 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001463 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1464 String8 uri("http://");
1465 uri.append(mUri.string() + 11);
1466
Andreas Huber54d09722010-10-12 11:34:37 -07001467 sp<LiveSource> liveSource = new LiveSource(uri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001468
Andreas Huber54d09722010-10-12 11:34:37 -07001469 mCachedSource = new NuCachedSource2(liveSource);
Andreas Huber4d61f602010-06-10 11:17:50 -07001470 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001471
1472 sp<MediaExtractor> extractor =
1473 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001474
Andreas Huber54d09722010-10-12 11:34:37 -07001475 static_cast<MPEG2TSExtractor *>(extractor.get())
1476 ->setLiveSource(liveSource);
1477
Andreas Huber4d61f602010-06-10 11:17:50 -07001478 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001479 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001480 if (mLooper == NULL) {
1481 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001482 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001483 mLooper->start(
1484 false /* runOnCallingThread */,
1485 false /* canCallJava */,
1486 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001487 }
1488
Mike Dodd8741dfa2010-08-12 16:04:35 -07001489 const char *startOfCodecString = &mUri.string()[13];
1490 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1491 if (startOfSlash1 == NULL) {
1492 return BAD_VALUE;
1493 }
1494 const char *startOfWidthString = &startOfSlash1[1];
1495 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1496 if (startOfSlash2 == NULL) {
1497 return BAD_VALUE;
1498 }
1499 const char *startOfHeightString = &startOfSlash2[1];
1500
1501 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1502 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1503 String8 heightString(startOfHeightString);
1504
Andreas Huber57648e42010-08-04 10:14:30 -07001505#if 0
1506 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1507 mLooper->registerHandler(mRTPPusher);
1508
1509 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1510 mLooper->registerHandler(mRTCPPusher);
1511#endif
1512
1513 mRTPSession = new ARTPSession;
1514 mLooper->registerHandler(mRTPSession);
1515
1516#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001517 // My AMR SDP
1518 static const char *raw =
1519 "v=0\r\n"
1520 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1521 "s=QuickTime\r\n"
1522 "t=0 0\r\n"
1523 "a=range:npt=0-315\r\n"
1524 "a=isma-compliance:2,2.0,2\r\n"
1525 "m=audio 5434 RTP/AVP 97\r\n"
1526 "c=IN IP4 127.0.0.1\r\n"
1527 "b=AS:30\r\n"
1528 "a=rtpmap:97 AMR/8000/1\r\n"
1529 "a=fmtp:97 octet-align\r\n";
1530#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001531 String8 sdp;
1532 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001533 "v=0\r\n"
1534 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1535 "s=QuickTime\r\n"
1536 "t=0 0\r\n"
1537 "a=range:npt=0-315\r\n"
1538 "a=isma-compliance:2,2.0,2\r\n"
1539 "m=video 5434 RTP/AVP 97\r\n"
1540 "c=IN IP4 127.0.0.1\r\n"
1541 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001542 "a=rtpmap:97 %s/90000\r\n"
1543 "a=cliprect:0,0,%s,%s\r\n"
1544 "a=framesize:97 %s-%s\r\n",
1545
1546 codecString.string(),
1547 heightString.string(), widthString.string(),
1548 widthString.string(), heightString.string()
1549 );
1550 const char *raw = sdp.string();
1551
Andreas Huber57648e42010-08-04 10:14:30 -07001552#endif
1553
1554 sp<ASessionDescription> desc = new ASessionDescription;
1555 CHECK(desc->setTo(raw, strlen(raw)));
1556
1557 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1558
1559 if (mRTPPusher != NULL) {
1560 mRTPPusher->start();
1561 }
1562
1563 if (mRTCPPusher != NULL) {
1564 mRTCPPusher->start();
1565 }
1566
1567 CHECK_EQ(mRTPSession->countTracks(), 1u);
1568 sp<MediaSource> source = mRTPSession->trackAt(0);
1569
1570#if 0
1571 bool eos;
1572 while (((APacketSource *)source.get())
1573 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1574 usleep(100000ll);
1575 }
1576#endif
1577
1578 const char *mime;
1579 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1580
1581 if (!strncasecmp("video/", mime, 6)) {
1582 setVideoSource(source);
1583 } else {
1584 CHECK(!strncasecmp("audio/", mime, 6));
1585 setAudioSource(source);
1586 }
1587
1588 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1589
1590 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001591 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1592 if (mLooper == NULL) {
1593 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001594 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001595 mLooper->start();
1596 }
1597 mRTSPController = new ARTSPController(mLooper);
1598 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001599
Andreas Huber7a747b82010-06-07 15:19:40 -07001600 LOGI("ARTSPController::connect returned %d", err);
1601
1602 if (err != OK) {
1603 mRTSPController.clear();
1604 return err;
1605 }
1606
1607 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001608 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001609 } else {
1610 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1611 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001612
1613 if (dataSource == NULL) {
1614 return UNKNOWN_ERROR;
1615 }
1616
1617 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1618
1619 if (extractor == NULL) {
1620 return UNKNOWN_ERROR;
1621 }
1622
Andreas Huberffdf4782010-02-09 14:05:43 -08001623 return setDataSource_l(extractor);
1624}
1625
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001626void AwesomePlayer::abortPrepare(status_t err) {
1627 CHECK(err != OK);
1628
1629 if (mIsAsyncPrepare) {
1630 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1631 }
1632
1633 mPrepareResult = err;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001634 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001635 mAsyncPrepareEvent = NULL;
1636 mPreparedCondition.broadcast();
1637}
1638
Andreas Huberf71daba2010-03-24 09:24:40 -07001639// static
1640bool AwesomePlayer::ContinuePreparation(void *cookie) {
1641 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1642
1643 return (me->mFlags & PREPARE_CANCELLED) == 0;
1644}
1645
Andreas Huber6be780e2010-02-08 14:40:30 -08001646void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001647 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001648
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001649 if (mFlags & PREPARE_CANCELLED) {
1650 LOGI("prepare was cancelled before doing anything");
1651 abortPrepare(UNKNOWN_ERROR);
1652 return;
1653 }
1654
1655 if (mUri.size() > 0) {
1656 status_t err = finishSetDataSource_l();
1657
1658 if (err != OK) {
1659 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001660 return;
1661 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001662 }
1663
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001664 if (mVideoTrack != NULL && mVideoSource == NULL) {
1665 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001666
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001667 if (err != OK) {
1668 abortPrepare(err);
1669 return;
1670 }
1671 }
1672
1673 if (mAudioTrack != NULL && mAudioSource == NULL) {
1674 status_t err = initAudioDecoder();
1675
1676 if (err != OK) {
1677 abortPrepare(err);
1678 return;
1679 }
1680 }
1681
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001682 mFlags |= PREPARING_CONNECTED;
1683
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001684 if (mCachedSource != NULL || mRTSPController != NULL) {
1685 postBufferingEvent_l();
1686 } else {
1687 finishAsyncPrepare_l();
1688 }
1689}
1690
1691void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001692 if (mIsAsyncPrepare) {
Andreas Hubere3c01832010-08-16 08:49:37 -07001693 if (mVideoSource == NULL) {
Andreas Huberffdf4782010-02-09 14:05:43 -08001694 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1695 } else {
Andreas Hubere3c01832010-08-16 08:49:37 -07001696 notifyVideoSize_l();
Andreas Huberffdf4782010-02-09 14:05:43 -08001697 }
1698
1699 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001700 }
1701
Andreas Huberffdf4782010-02-09 14:05:43 -08001702 mPrepareResult = OK;
Andreas Hubereaf2c5a2010-10-19 12:18:51 -07001703 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001704 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001705 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001706 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001707}
1708
Andreas Huberba7ec912010-02-12 10:42:02 -08001709status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001710 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001711 Mutex::Autolock autoLock(mLock);
1712
1713 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001714 if (mLastVideoBuffer == NULL) {
1715 //go into here if video is suspended again
1716 //after resuming without being played between
1717 //them
1718 SuspensionState *state = mSuspensionState;
1719 mSuspensionState = NULL;
1720 reset_l();
1721 mSuspensionState = state;
1722 return OK;
1723 }
1724
1725 delete mSuspensionState;
1726 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001727 }
1728
Andreas Huberedbb4d82010-03-12 08:59:22 -08001729 if (mFlags & PREPARING) {
1730 mFlags |= PREPARE_CANCELLED;
1731 if (mConnectingDataSource != NULL) {
1732 LOGI("interrupting the connection process");
1733 mConnectingDataSource->disconnect();
1734 }
1735 }
1736
Andreas Huberba7ec912010-02-12 10:42:02 -08001737 while (mFlags & PREPARING) {
1738 mPreparedCondition.wait(mLock);
1739 }
1740
1741 SuspensionState *state = new SuspensionState;
1742 state->mUri = mUri;
1743 state->mUriHeaders = mUriHeaders;
1744 state->mFileSource = mFileSource;
1745
Andreas Huber9fee0b22010-09-03 14:09:21 -07001746 state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001747 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001748
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001749 if (mLastVideoBuffer) {
1750 size_t size = mLastVideoBuffer->range_length();
Andreas Huber1e194162010-10-06 16:43:57 -07001751
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001752 if (size) {
Andreas Huber1e194162010-10-06 16:43:57 -07001753 int32_t unreadable;
1754 if (!mLastVideoBuffer->meta_data()->findInt32(
1755 kKeyIsUnreadable, &unreadable)
1756 || unreadable == 0) {
1757 state->mLastVideoFrameSize = size;
1758 state->mLastVideoFrame = malloc(size);
1759 memcpy(state->mLastVideoFrame,
1760 (const uint8_t *)mLastVideoBuffer->data()
1761 + mLastVideoBuffer->range_offset(),
1762 size);
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001763
Andreas Huber1e194162010-10-06 16:43:57 -07001764 state->mVideoWidth = mVideoWidth;
1765 state->mVideoHeight = mVideoHeight;
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001766
Andreas Huber1e194162010-10-06 16:43:57 -07001767 sp<MetaData> meta = mVideoSource->getFormat();
1768 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1769 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1770 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1771 } else {
1772 LOGV("Unable to save last video frame, we have no access to "
1773 "the decoded video data.");
1774 }
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001775 }
1776 }
1777
Andreas Huberba7ec912010-02-12 10:42:02 -08001778 reset_l();
1779
1780 mSuspensionState = state;
1781
1782 return OK;
1783}
1784
1785status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001786 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001787 Mutex::Autolock autoLock(mLock);
1788
1789 if (mSuspensionState == NULL) {
1790 return INVALID_OPERATION;
1791 }
1792
1793 SuspensionState *state = mSuspensionState;
1794 mSuspensionState = NULL;
1795
1796 status_t err;
1797 if (state->mFileSource != NULL) {
1798 err = setDataSource_l(state->mFileSource);
1799
1800 if (err == OK) {
1801 mFileSource = state->mFileSource;
1802 }
1803 } else {
1804 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1805 }
1806
1807 if (err != OK) {
1808 delete state;
1809 state = NULL;
1810
1811 return err;
1812 }
1813
1814 seekTo_l(state->mPositionUs);
1815
Andreas Huber9fee0b22010-09-03 14:09:21 -07001816 mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001817
Andreas Hubere3c01832010-08-16 08:49:37 -07001818 if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001819 mVideoRenderer =
1820 new AwesomeLocalRenderer(
1821 true, // previewOnly
1822 "",
1823 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1824 mISurface,
Andreas Hubere3c01832010-08-16 08:49:37 -07001825 mSurface,
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001826 state->mVideoWidth,
1827 state->mVideoHeight,
1828 state->mDecodedWidth,
1829 state->mDecodedHeight);
1830
1831 mVideoRendererIsPreview = true;
1832
1833 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1834 state->mLastVideoFrame, state->mLastVideoFrameSize);
1835 }
1836
Andreas Huberba7ec912010-02-12 10:42:02 -08001837 if (state->mFlags & PLAYING) {
1838 play_l();
1839 }
1840
Gloria Wangb19da8e2010-04-12 17:13:06 -07001841 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001842 state = NULL;
1843
1844 return OK;
1845}
1846
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001847uint32_t AwesomePlayer::flags() const {
1848 return mExtractorFlags;
1849}
1850
Andreas Huber2b359ed2010-09-28 11:56:39 -07001851void AwesomePlayer::postAudioEOS() {
1852 postCheckAudioStatusEvent_l();
1853}
1854
1855void AwesomePlayer::postAudioSeekComplete() {
1856 postCheckAudioStatusEvent_l();
1857}
1858
Andreas Huber27366fc2009-11-20 09:32:46 -08001859} // namespace android