blob: 57bea8c2ae62660d28a4ab499962005f40e5c6a8 [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
Mathias Agopian000479f2010-02-09 17:46:37 -080048#include <surfaceflinger/ISurface.h>
49
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,
104 const sp<ISurface> &surface,
105 size_t displayWidth, size_t displayHeight,
106 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800107 : mTarget(NULL),
108 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800109 init(previewOnly, componentName,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800110 colorFormat, surface, displayWidth,
111 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800112 }
113
114 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800115 render((const uint8_t *)buffer->data() + buffer->range_offset(),
116 buffer->range_length());
117 }
118
119 void render(const void *data, size_t size) {
120 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800121 }
122
123protected:
124 virtual ~AwesomeLocalRenderer() {
125 delete mTarget;
126 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800127
128 if (mLibHandle) {
129 dlclose(mLibHandle);
130 mLibHandle = NULL;
131 }
Andreas Huber1314e732009-12-14 14:18:22 -0800132 }
133
134private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800135 VideoRenderer *mTarget;
136 void *mLibHandle;
137
138 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800139 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800140 const char *componentName,
141 OMX_COLOR_FORMATTYPE colorFormat,
142 const sp<ISurface> &surface,
143 size_t displayWidth, size_t displayHeight,
144 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800145
146 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
147 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
148};
149
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800150void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800151 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800152 const char *componentName,
153 OMX_COLOR_FORMATTYPE colorFormat,
154 const sp<ISurface> &surface,
155 size_t displayWidth, size_t displayHeight,
156 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800157 if (!previewOnly) {
158 // We will stick to the vanilla software-color-converting renderer
159 // for "previewOnly" mode, to avoid unneccessarily switching overlays
160 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800161
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800162 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800163
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800164 if (mLibHandle) {
165 typedef VideoRenderer *(*CreateRendererFunc)(
166 const sp<ISurface> &surface,
167 const char *componentName,
168 OMX_COLOR_FORMATTYPE colorFormat,
169 size_t displayWidth, size_t displayHeight,
170 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800171
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800172 CreateRendererFunc func =
173 (CreateRendererFunc)dlsym(
174 mLibHandle,
175 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
176 "OMX_COLOR_FORMATTYPEjjjj");
177
178 if (func) {
179 mTarget =
180 (*func)(surface, componentName, colorFormat,
181 displayWidth, displayHeight,
182 decodedWidth, decodedHeight);
183 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800184 }
185 }
186
187 if (mTarget == NULL) {
188 mTarget = new SoftwareRenderer(
189 colorFormat, surface, displayWidth, displayHeight,
190 decodedWidth, decodedHeight);
191 }
192}
193
Andreas Huber27366fc2009-11-20 09:32:46 -0800194AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800195 : mQueueStarted(false),
196 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800197 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800198 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800199 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700200 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800201 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800202 mVideoBuffer(NULL),
203 mSuspensionState(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800204 CHECK_EQ(mClient.connect(), OK);
205
206 DataSource::RegisterDefaultSniffers();
207
Andreas Huber6be780e2010-02-08 14:40:30 -0800208 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800209 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800210 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800211 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800212 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800213 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800214
215 mCheckAudioStatusEvent = new AwesomeEvent(
216 this, &AwesomePlayer::onCheckAudioStatus);
217
Andreas Huber70d10c02010-02-03 11:37:29 -0800218 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800219
Andreas Huber27366fc2009-11-20 09:32:46 -0800220 reset();
221}
222
223AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800224 if (mQueueStarted) {
225 mQueue.stop();
226 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800227
228 reset();
229
230 mClient.disconnect();
231}
232
Andreas Huberb9e63832010-01-26 16:20:10 -0800233void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800234 mQueue.cancelEvent(mVideoEvent->eventID());
235 mVideoEventPending = false;
236 mQueue.cancelEvent(mStreamDoneEvent->eventID());
237 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800238 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
239 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800240
241 if (!keepBufferingGoing) {
242 mQueue.cancelEvent(mBufferingEvent->eventID());
243 mBufferingEventPending = false;
244 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800245}
246
Andreas Hubera3f43842010-01-21 10:28:45 -0800247void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800248 Mutex::Autolock autoLock(mLock);
249 mListener = listener;
250}
251
Andreas Huber433c9ac2010-01-27 16:49:05 -0800252status_t AwesomePlayer::setDataSource(
253 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800254 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800255 return setDataSource_l(uri, headers);
256}
Andreas Huber27366fc2009-11-20 09:32:46 -0800257
Andreas Huberba7ec912010-02-12 10:42:02 -0800258status_t AwesomePlayer::setDataSource_l(
259 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800260 reset_l();
261
Andreas Huberffdf4782010-02-09 14:05:43 -0800262 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800263
Andreas Huberffdf4782010-02-09 14:05:43 -0800264 if (headers) {
265 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800266 }
267
Andreas Huberffdf4782010-02-09 14:05:43 -0800268 // The actual work will be done during preparation in the call to
269 // ::finishSetDataSource_l to avoid blocking the calling thread in
270 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800271
Andreas Huberffdf4782010-02-09 14:05:43 -0800272 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800273}
274
275status_t AwesomePlayer::setDataSource(
276 int fd, int64_t offset, int64_t length) {
277 Mutex::Autolock autoLock(mLock);
278
279 reset_l();
280
Andreas Huberba7ec912010-02-12 10:42:02 -0800281 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800282
Andreas Huberba7ec912010-02-12 10:42:02 -0800283 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800284
285 if (err != OK) {
286 return err;
287 }
288
Andreas Huberba7ec912010-02-12 10:42:02 -0800289 mFileSource = dataSource;
290
291 return setDataSource_l(dataSource);
292}
293
294status_t AwesomePlayer::setDataSource_l(
295 const sp<DataSource> &dataSource) {
296 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800297
298 if (extractor == NULL) {
299 return UNKNOWN_ERROR;
300 }
301
302 return setDataSource_l(extractor);
303}
304
305status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700306 // Attempt to approximate overall stream bitrate by summing all
307 // tracks' individual bitrates, if not all of them advertise bitrate,
308 // we have to fail.
309
310 int64_t totalBitRate = 0;
311
312 for (size_t i = 0; i < extractor->countTracks(); ++i) {
313 sp<MetaData> meta = extractor->getTrackMetaData(i);
314
315 int32_t bitrate;
316 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
317 totalBitRate = -1;
318 break;
319 }
320
321 totalBitRate += bitrate;
322 }
323
324 mBitrate = totalBitRate;
325
326 LOGV("mBitrate = %lld bits/sec", mBitrate);
327
Andreas Huber27366fc2009-11-20 09:32:46 -0800328 bool haveAudio = false;
329 bool haveVideo = false;
330 for (size_t i = 0; i < extractor->countTracks(); ++i) {
331 sp<MetaData> meta = extractor->getTrackMetaData(i);
332
333 const char *mime;
334 CHECK(meta->findCString(kKeyMIMEType, &mime));
335
336 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800337 setVideoSource(extractor->getTrack(i));
338 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800339 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800340 setAudioSource(extractor->getTrack(i));
341 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700342
Andreas Huber1913c1a2010-10-04 11:09:31 -0700343 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
344 // Only do this for vorbis audio, none of the other audio
345 // formats even support this ringtone specific hack and
346 // retrieving the metadata on some extractors may turn out
347 // to be very expensive.
348 sp<MetaData> fileMeta = extractor->getMetaData();
349 int32_t loop;
350 if (fileMeta != NULL
351 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
352 mFlags |= AUTO_LOOPING;
353 }
Andreas Huber9fee0b22010-09-03 14:09:21 -0700354 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800355 }
356
357 if (haveAudio && haveVideo) {
358 break;
359 }
360 }
361
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700362 if (!haveAudio && !haveVideo) {
363 return UNKNOWN_ERROR;
364 }
365
366 mExtractorFlags = extractor->flags();
367
368 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800369}
370
371void AwesomePlayer::reset() {
372 Mutex::Autolock autoLock(mLock);
373 reset_l();
374}
375
376void AwesomePlayer::reset_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -0800377 if (mFlags & PREPARING) {
378 mFlags |= PREPARE_CANCELLED;
379 if (mConnectingDataSource != NULL) {
380 LOGI("interrupting the connection process");
381 mConnectingDataSource->disconnect();
382 }
383 }
384
Andreas Huberffdf4782010-02-09 14:05:43 -0800385 while (mFlags & PREPARING) {
386 mPreparedCondition.wait(mLock);
387 }
388
Andreas Huber27366fc2009-11-20 09:32:46 -0800389 cancelPlayerEvents();
390
Andreas Huber4d61f602010-06-10 11:17:50 -0700391 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800392 mAudioTrack.clear();
393 mVideoTrack.clear();
394
Andreas Huberba7ec912010-02-12 10:42:02 -0800395 // Shutdown audio first, so that the respone to the reset request
396 // appears to happen instantaneously as far as the user is concerned
397 // If we did this later, audio would continue playing while we
398 // shutdown the video-related resources and the player appear to
399 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800400 if (mAudioPlayer == NULL && mAudioSource != NULL) {
401 // If we had an audio player, it would have effectively
402 // taken possession of the audio source and stopped it when
403 // _it_ is stopped. Otherwise this is still our responsibility.
404 mAudioSource->stop();
405 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800406 mAudioSource.clear();
407
Andreas Huberba7ec912010-02-12 10:42:02 -0800408 mTimeSource = NULL;
409
410 delete mAudioPlayer;
411 mAudioPlayer = NULL;
412
Andreas Huber3522b5a52010-01-22 14:36:53 -0800413 mVideoRenderer.clear();
414
Andreas Huber27366fc2009-11-20 09:32:46 -0800415 if (mLastVideoBuffer) {
416 mLastVideoBuffer->release();
417 mLastVideoBuffer = NULL;
418 }
419
420 if (mVideoBuffer) {
421 mVideoBuffer->release();
422 mVideoBuffer = NULL;
423 }
424
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700425 if (mRTSPController != NULL) {
426 mRTSPController->disconnect();
427 mRTSPController.clear();
428 }
429
Andreas Huber57648e42010-08-04 10:14:30 -0700430 mRTPPusher.clear();
431 mRTCPPusher.clear();
432 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700433
Andreas Huber27366fc2009-11-20 09:32:46 -0800434 if (mVideoSource != NULL) {
435 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800436
437 // The following hack is necessary to ensure that the OMX
438 // component is completely released by the time we may try
439 // to instantiate it again.
440 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800441 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800442 while (tmp.promote() != NULL) {
443 usleep(1000);
444 }
445 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800446 }
447
Andreas Huber27366fc2009-11-20 09:32:46 -0800448 mDurationUs = -1;
449 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700450 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800451 mVideoWidth = mVideoHeight = -1;
452 mTimeSourceDeltaUs = 0;
453 mVideoTimeUs = 0;
454
455 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700456 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800457 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800458
Andreas Huberffdf4782010-02-09 14:05:43 -0800459 mUri.setTo("");
460 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800461
462 mFileSource.clear();
463
464 delete mSuspensionState;
465 mSuspensionState = NULL;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700466
467 mBitrate = -1;
Andreas Huber27366fc2009-11-20 09:32:46 -0800468}
469
Andreas Huber6be780e2010-02-08 14:40:30 -0800470void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800471 if (mListener != NULL) {
472 sp<MediaPlayerBase> listener = mListener.promote();
473
474 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800475 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800476 }
477 }
478}
479
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700480bool AwesomePlayer::getBitrate(int64_t *bitrate) {
481 off_t size;
482 if (mDurationUs >= 0 && mCachedSource != NULL
483 && mCachedSource->getSize(&size) == OK) {
484 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec
485 return true;
486 }
487
488 if (mBitrate >= 0) {
489 *bitrate = mBitrate;
490 return true;
491 }
492
493 *bitrate = 0;
494
495 return false;
496}
497
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700498// Returns true iff cached duration is available/applicable.
499bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700500 int64_t bitrate;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700501
502 if (mRTSPController != NULL) {
503 *durationUs = mRTSPController->getQueueDurationUs(eos);
504 return true;
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700505 } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700506 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
507 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
508 return true;
509 }
510
511 return false;
512}
513
Andreas Huberb9e63832010-01-26 16:20:10 -0800514void AwesomePlayer::onBufferingUpdate() {
515 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800516 if (!mBufferingEventPending) {
517 return;
518 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800519 mBufferingEventPending = false;
520
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700521 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700522 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700523 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700524
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700525 if (eos) {
526 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
Andreas Huber05f67872010-10-04 11:36:39 -0700527 if (mFlags & PREPARING) {
528 LOGV("cache has reached EOS, prepare is done.");
529 finishAsyncPrepare_l();
530 }
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700531 } else {
Andreas Huber4deb3eb2010-10-12 16:55:11 -0700532 int64_t bitrate;
533 if (getBitrate(&bitrate)) {
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700534 size_t cachedSize = mCachedSource->cachedSize();
535 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
536
537 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
538 if (percentage > 100) {
539 percentage = 100;
540 }
541
542 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
543 } else {
544 // We don't know the bitrate of the stream, use absolute size
545 // limits to maintain the cache.
546
Andreas Huber54d09722010-10-12 11:34:37 -0700547 const size_t kLowWaterMarkBytes = 40000;
548 const size_t kHighWaterMarkBytes = 200000;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700549
550 if ((mFlags & PLAYING) && !eos
551 && (cachedDataRemaining < kLowWaterMarkBytes)) {
552 LOGI("cache is running low (< %d) , pausing.",
553 kLowWaterMarkBytes);
554 mFlags |= CACHE_UNDERRUN;
555 pause_l();
556 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
557 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
558 if (mFlags & CACHE_UNDERRUN) {
559 LOGI("cache has filled up (> %d), resuming.",
560 kHighWaterMarkBytes);
561 mFlags &= ~CACHE_UNDERRUN;
562 play_l();
563 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
564 } else if (mFlags & PREPARING) {
565 LOGV("cache has filled up (> %d), prepare is done",
566 kHighWaterMarkBytes);
567 finishAsyncPrepare_l();
568 }
569 }
570 }
571 }
572 }
573
574 int64_t cachedDurationUs;
575 bool eos;
576 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700577 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700578 && (cachedDurationUs < kLowWaterMarkUs)) {
579 LOGI("cache is running low (%.2f secs) , pausing.",
580 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700581 mFlags |= CACHE_UNDERRUN;
582 pause_l();
583 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700584 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
585 if (mFlags & CACHE_UNDERRUN) {
586 LOGI("cache has filled up (%.2f secs), resuming.",
587 cachedDurationUs / 1E6);
588 mFlags &= ~CACHE_UNDERRUN;
589 play_l();
590 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
591 } else if (mFlags & PREPARING) {
592 LOGV("cache has filled up (%.2f secs), prepare is done",
593 cachedDurationUs / 1E6);
594 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700595 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700596 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800597 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700598
Andreas Huber4d61f602010-06-10 11:17:50 -0700599 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800600}
601
Andreas Huber4c19bf92010-09-08 14:32:20 -0700602void AwesomePlayer::partial_reset_l() {
603 // Only reset the video renderer and shut down the video decoder.
604 // Then instantiate a new video decoder and resume video playback.
605
606 mVideoRenderer.clear();
607
608 if (mLastVideoBuffer) {
609 mLastVideoBuffer->release();
610 mLastVideoBuffer = NULL;
611 }
612
613 if (mVideoBuffer) {
614 mVideoBuffer->release();
615 mVideoBuffer = NULL;
616 }
617
618 {
619 mVideoSource->stop();
620
621 // The following hack is necessary to ensure that the OMX
622 // component is completely released by the time we may try
623 // to instantiate it again.
624 wp<MediaSource> tmp = mVideoSource;
625 mVideoSource.clear();
626 while (tmp.promote() != NULL) {
627 usleep(1000);
628 }
629 IPCThreadState::self()->flushCommands();
630 }
631
632 CHECK_EQ(OK, initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData));
633}
634
Andreas Huber27366fc2009-11-20 09:32:46 -0800635void AwesomePlayer::onStreamDone() {
636 // Posted whenever any stream finishes playing.
637
638 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800639 if (!mStreamDoneEventPending) {
640 return;
641 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800642 mStreamDoneEventPending = false;
643
Andreas Huber4c19bf92010-09-08 14:32:20 -0700644 if (mStreamDoneStatus == INFO_DISCONTINUITY) {
645 // This special status is returned because an http live stream's
646 // video stream switched to a different bandwidth at this point
647 // and future data may have been encoded using different parameters.
648 // This requires us to shutdown the video decoder and reinstantiate
649 // a fresh one.
650
651 LOGV("INFO_DISCONTINUITY");
652
653 CHECK(mVideoSource != NULL);
654
655 partial_reset_l();
656 postVideoEvent_l();
657 return;
658 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
Andreas Huber971305d2010-07-07 13:35:27 -0700659 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
660
661 notifyListener_l(
662 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
663
Andreas Huberc743f452010-10-05 10:25:34 -0700664 pause_l(true /* at eos */);
Andreas Huber971305d2010-07-07 13:35:27 -0700665
666 mFlags |= AT_EOS;
667 return;
668 }
669
670 const bool allDone =
671 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
672 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
673
674 if (!allDone) {
675 return;
676 }
677
Andreas Huber9fee0b22010-09-03 14:09:21 -0700678 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800679 seekTo_l(0);
680
Andreas Huber7085b6842010-02-03 16:02:02 -0800681 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800682 postVideoEvent_l();
683 }
684 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700685 LOGV("MEDIA_PLAYBACK_COMPLETE");
686 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800687
Andreas Huberc743f452010-10-05 10:25:34 -0700688 pause_l(true /* at eos */);
Andreas Huber406a18b2010-02-18 16:45:13 -0800689
690 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800691 }
692}
693
694status_t AwesomePlayer::play() {
695 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700696
697 mFlags &= ~CACHE_UNDERRUN;
698
Andreas Huberba7ec912010-02-12 10:42:02 -0800699 return play_l();
700}
Andreas Huber27366fc2009-11-20 09:32:46 -0800701
Andreas Huberba7ec912010-02-12 10:42:02 -0800702status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800703 if (mFlags & PLAYING) {
704 return OK;
705 }
706
Andreas Huberffdf4782010-02-09 14:05:43 -0800707 if (!(mFlags & PREPARED)) {
708 status_t err = prepare_l();
709
710 if (err != OK) {
711 return err;
712 }
713 }
714
Andreas Huber27366fc2009-11-20 09:32:46 -0800715 mFlags |= PLAYING;
716 mFlags |= FIRST_FRAME;
717
Andreas Huberc1d5c922009-12-10 15:49:04 -0800718 bool deferredAudioSeek = false;
719
Andreas Huber27366fc2009-11-20 09:32:46 -0800720 if (mAudioSource != NULL) {
721 if (mAudioPlayer == NULL) {
722 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700723 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800724 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800725
726 // We've already started the MediaSource in order to enable
727 // the prefetcher to read its data.
728 status_t err = mAudioPlayer->start(
729 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800730
731 if (err != OK) {
732 delete mAudioPlayer;
733 mAudioPlayer = NULL;
734
735 mFlags &= ~(PLAYING | FIRST_FRAME);
736
737 return err;
738 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800739
Andreas Huber27366fc2009-11-20 09:32:46 -0800740 mTimeSource = mAudioPlayer;
741
Andreas Huberc1d5c922009-12-10 15:49:04 -0800742 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800743
744 mWatchForAudioSeekComplete = false;
745 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800746 }
747 } else {
748 mAudioPlayer->resume();
749 }
750 }
751
752 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700753 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800754 }
755
756 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800757 // Kick off video playback
758 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800759 }
760
Andreas Huberc1d5c922009-12-10 15:49:04 -0800761 if (deferredAudioSeek) {
762 // If there was a seek request while we were paused
763 // and we're just starting up again, honor the request now.
764 seekAudioIfNecessary_l();
765 }
766
Andreas Huber406a18b2010-02-18 16:45:13 -0800767 if (mFlags & AT_EOS) {
768 // Legacy behaviour, if a stream finishes playing and then
769 // is started again, we play from the start...
770 seekTo_l(0);
771 }
772
Andreas Huber27366fc2009-11-20 09:32:46 -0800773 return OK;
774}
775
776void AwesomePlayer::initRenderer_l() {
777 if (mISurface != NULL) {
778 sp<MetaData> meta = mVideoSource->getFormat();
779
780 int32_t format;
781 const char *component;
782 int32_t decodedWidth, decodedHeight;
783 CHECK(meta->findInt32(kKeyColorFormat, &format));
784 CHECK(meta->findCString(kKeyDecoderComponent, &component));
785 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
786 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
787
Andreas Hubera67d5382009-12-10 15:32:12 -0800788 mVideoRenderer.clear();
789
790 // Must ensure that mVideoRenderer's destructor is actually executed
791 // before creating a new one.
792 IPCThreadState::self()->flushCommands();
793
Andreas Huber1314e732009-12-14 14:18:22 -0800794 if (!strncmp("OMX.", component, 4)) {
795 // Our OMX codecs allocate buffers on the media_server side
796 // therefore they require a remote IOMXRenderer that knows how
797 // to display them.
798 mVideoRenderer = new AwesomeRemoteRenderer(
799 mClient.interface()->createRenderer(
800 mISurface, component,
801 (OMX_COLOR_FORMATTYPE)format,
802 decodedWidth, decodedHeight,
803 mVideoWidth, mVideoHeight));
804 } else {
805 // Other decoders are instantiated locally and as a consequence
806 // allocate their buffers in local address space.
807 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800808 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800809 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800810 (OMX_COLOR_FORMATTYPE)format,
811 mISurface,
812 mVideoWidth, mVideoHeight,
813 decodedWidth, decodedHeight);
814 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800815 }
816}
817
818status_t AwesomePlayer::pause() {
819 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700820
821 mFlags &= ~CACHE_UNDERRUN;
822
Andreas Huber27366fc2009-11-20 09:32:46 -0800823 return pause_l();
824}
825
Andreas Huberc743f452010-10-05 10:25:34 -0700826status_t AwesomePlayer::pause_l(bool at_eos) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800827 if (!(mFlags & PLAYING)) {
828 return OK;
829 }
830
Andreas Huberb9e63832010-01-26 16:20:10 -0800831 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800832
833 if (mAudioPlayer != NULL) {
Andreas Huberc743f452010-10-05 10:25:34 -0700834 if (at_eos) {
835 // If we played the audio stream to completion we
836 // want to make sure that all samples remaining in the audio
837 // track's queue are played out.
838 mAudioPlayer->pause(true /* playPendingSamples */);
839 } else {
840 mAudioPlayer->pause();
841 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800842 }
843
844 mFlags &= ~PLAYING;
845
846 return OK;
847}
848
849bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700850 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800851}
852
853void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
854 Mutex::Autolock autoLock(mLock);
855
856 mISurface = isurface;
857}
858
859void AwesomePlayer::setAudioSink(
860 const sp<MediaPlayerBase::AudioSink> &audioSink) {
861 Mutex::Autolock autoLock(mLock);
862
863 mAudioSink = audioSink;
864}
865
866status_t AwesomePlayer::setLooping(bool shouldLoop) {
867 Mutex::Autolock autoLock(mLock);
868
869 mFlags = mFlags & ~LOOPING;
870
871 if (shouldLoop) {
872 mFlags |= LOOPING;
873 }
874
875 return OK;
876}
877
878status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700879 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800880
881 if (mDurationUs < 0) {
882 return UNKNOWN_ERROR;
883 }
884
885 *durationUs = mDurationUs;
886
887 return OK;
888}
889
890status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -0700891 if (mRTSPController != NULL) {
892 *positionUs = mRTSPController->getNormalPlayTimeUs();
893 }
894 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700895 *positionUs = mSeekTimeUs;
896 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700897 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800898 *positionUs = mVideoTimeUs;
899 } else if (mAudioPlayer != NULL) {
900 *positionUs = mAudioPlayer->getMediaTimeUs();
901 } else {
902 *positionUs = 0;
903 }
904
905 return OK;
906}
907
908status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber10b9b3f2010-10-08 10:16:24 -0700909 if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700910 Mutex::Autolock autoLock(mLock);
911 return seekTo_l(timeUs);
912 }
913
914 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800915}
916
Andreas Huber0c46b692010-10-08 15:21:08 -0700917// static
918void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
919 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
920}
921
922void AwesomePlayer::onRTSPSeekDone() {
923 notifyListener_l(MEDIA_SEEK_COMPLETE);
924 mSeekNotificationSent = true;
925}
926
Andreas Huber27366fc2009-11-20 09:32:46 -0800927status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700928 if (mRTSPController != NULL) {
Andreas Huber0c46b692010-10-08 15:21:08 -0700929 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700930 return OK;
931 }
932
Andreas Huber4d61f602010-06-10 11:17:50 -0700933 if (mFlags & CACHE_UNDERRUN) {
934 mFlags &= ~CACHE_UNDERRUN;
935 play_l();
936 }
937
Andreas Huber27366fc2009-11-20 09:32:46 -0800938 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700939 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800940 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700941 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -0800942
943 seekAudioIfNecessary_l();
944
Andreas Huber8e2b9412010-03-31 09:40:15 -0700945 if (!(mFlags & PLAYING)) {
946 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
947 " immediately.");
948
949 notifyListener_l(MEDIA_SEEK_COMPLETE);
950 mSeekNotificationSent = true;
951 }
952
Andreas Huber27366fc2009-11-20 09:32:46 -0800953 return OK;
954}
955
956void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800957 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800958 mAudioPlayer->seekTo(mSeekTimeUs);
959
Andreas Huber70d10c02010-02-03 11:37:29 -0800960 mWatchForAudioSeekComplete = true;
961 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700962 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800963 }
964}
965
966status_t AwesomePlayer::getVideoDimensions(
967 int32_t *width, int32_t *height) const {
968 Mutex::Autolock autoLock(mLock);
969
970 if (mVideoWidth < 0 || mVideoHeight < 0) {
971 return UNKNOWN_ERROR;
972 }
973
974 *width = mVideoWidth;
975 *height = mVideoHeight;
976
977 return OK;
978}
979
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800980void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
981 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800982
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800983 mAudioTrack = source;
984}
985
986status_t AwesomePlayer::initAudioDecoder() {
987 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800988
989 const char *mime;
990 CHECK(meta->findCString(kKeyMIMEType, &mime));
991
992 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800993 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800994 } else {
995 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800996 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800997 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800998 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800999 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001000
1001 if (mAudioSource != NULL) {
1002 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001003 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001004 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001005 if (mDurationUs < 0 || durationUs > mDurationUs) {
1006 mDurationUs = durationUs;
1007 }
1008 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001009
Andreas Huber3c78a1b2010-05-13 09:15:21 -07001010 status_t err = mAudioSource->start();
1011
1012 if (err != OK) {
1013 mAudioSource.clear();
1014 return err;
1015 }
Andreas Huberd0332ad2010-04-12 16:05:57 -07001016 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
1017 // For legacy reasons we're simply going to ignore the absence
1018 // of an audio decoder for QCELP instead of aborting playback
1019 // altogether.
1020 return OK;
1021 }
Andreas Huberdc9927d2010-03-08 15:46:13 -08001022
Andreas Huber27366fc2009-11-20 09:32:46 -08001023 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
1024}
1025
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001026void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
1027 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -08001028
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001029 mVideoTrack = source;
1030}
1031
Andreas Huber4c19bf92010-09-08 14:32:20 -07001032status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001033 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001034 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -08001035 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -07001036 mVideoTrack,
1037 NULL, flags);
Andreas Huber27366fc2009-11-20 09:32:46 -08001038
1039 if (mVideoSource != NULL) {
1040 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001041 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -07001042 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -08001043 if (mDurationUs < 0 || durationUs > mDurationUs) {
1044 mDurationUs = durationUs;
1045 }
1046 }
1047
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001048 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
1049 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -08001050
Andreas Huber1919e5a2010-05-20 10:37:06 -07001051 status_t err = mVideoSource->start();
1052
1053 if (err != OK) {
1054 mVideoSource.clear();
1055 return err;
1056 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001057 }
1058
1059 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
1060}
1061
Andreas Huber6be780e2010-02-08 14:40:30 -08001062void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -08001063 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -08001064 if (!mVideoEventPending) {
1065 // The event has been cancelled in reset_l() but had already
1066 // been scheduled for execution at that time.
1067 return;
1068 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001069 mVideoEventPending = false;
1070
1071 if (mSeeking) {
1072 if (mLastVideoBuffer) {
1073 mLastVideoBuffer->release();
1074 mLastVideoBuffer = NULL;
1075 }
1076
1077 if (mVideoBuffer) {
1078 mVideoBuffer->release();
1079 mVideoBuffer = NULL;
1080 }
Andreas Huber4d61f602010-06-10 11:17:50 -07001081
1082 if (mCachedSource != NULL && mAudioSource != NULL) {
1083 // We're going to seek the video source first, followed by
1084 // the audio source.
1085 // In order to avoid jumps in the DataSource offset caused by
1086 // the audio codec prefetching data from the old locations
1087 // while the video codec is already reading data from the new
1088 // locations, we'll "pause" the audio source, causing it to
1089 // stop reading input data until a subsequent seek.
1090
1091 if (mAudioPlayer != NULL) {
1092 mAudioPlayer->pause();
1093 }
1094 mAudioSource->pause();
1095 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001096 }
1097
1098 if (!mVideoBuffer) {
1099 MediaSource::ReadOptions options;
1100 if (mSeeking) {
1101 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1102
Andreas Huber6624c9f2010-07-20 15:04:28 -07001103 options.setSeekTo(
1104 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001105 }
1106 for (;;) {
1107 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001108 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001109
1110 if (err != OK) {
1111 CHECK_EQ(mVideoBuffer, NULL);
1112
1113 if (err == INFO_FORMAT_CHANGED) {
1114 LOGV("VideoSource signalled format change.");
1115
Andreas Huber7085b6842010-02-03 16:02:02 -08001116 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001117 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001118 initRenderer_l();
1119 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001120 continue;
1121 }
1122
Andreas Huber971305d2010-07-07 13:35:27 -07001123 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001124 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001125 return;
1126 }
1127
Andreas Hubera67d5382009-12-10 15:32:12 -08001128 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001129 // Some decoders, notably the PV AVC software decoder
1130 // return spurious empty buffers that we just want to ignore.
1131
Andreas Hubera67d5382009-12-10 15:32:12 -08001132 mVideoBuffer->release();
1133 mVideoBuffer = NULL;
1134 continue;
1135 }
1136
Andreas Huber27366fc2009-11-20 09:32:46 -08001137 break;
1138 }
1139 }
1140
1141 int64_t timeUs;
1142 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1143
Andreas Huber252573c2010-03-26 10:17:17 -07001144 {
1145 Mutex::Autolock autoLock(mMiscStateLock);
1146 mVideoTimeUs = timeUs;
1147 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001148
1149 if (mSeeking) {
1150 if (mAudioPlayer != NULL) {
1151 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
1152
1153 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -07001154 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -08001155 mWatchForAudioSeekComplete = true;
1156 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001157 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001158 // If we're playing video only, report seek complete now,
1159 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -08001160 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -08001161 }
1162
1163 mFlags |= FIRST_FRAME;
1164 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001165 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001166 }
1167
Andreas Huber971305d2010-07-07 13:35:27 -07001168 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1169
Andreas Huber27366fc2009-11-20 09:32:46 -08001170 if (mFlags & FIRST_FRAME) {
1171 mFlags &= ~FIRST_FRAME;
1172
Andreas Huber971305d2010-07-07 13:35:27 -07001173 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001174 }
1175
1176 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001177 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001178 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1179 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1180 }
1181
Andreas Huber971305d2010-07-07 13:35:27 -07001182 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001183
1184 int64_t latenessUs = nowUs - timeUs;
1185
Andreas Huberf88f8442010-08-10 11:18:36 -07001186 if (mRTPSession != NULL) {
1187 // We'll completely ignore timestamps for gtalk videochat
1188 // and we'll play incoming video as fast as we get it.
1189 latenessUs = 0;
1190 }
1191
Andreas Huber24b0a952009-11-23 14:02:00 -08001192 if (latenessUs > 40000) {
1193 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001194 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001195
1196 mVideoBuffer->release();
1197 mVideoBuffer = NULL;
1198
1199 postVideoEvent_l();
1200 return;
1201 }
1202
1203 if (latenessUs < -10000) {
1204 // We're more than 10ms early.
1205
1206 postVideoEvent_l(10000);
1207 return;
1208 }
1209
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001210 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1211 mVideoRendererIsPreview = false;
1212
Andreas Huber7085b6842010-02-03 16:02:02 -08001213 initRenderer_l();
1214 }
1215
1216 if (mVideoRenderer != NULL) {
1217 mVideoRenderer->render(mVideoBuffer);
1218 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001219
1220 if (mLastVideoBuffer) {
1221 mLastVideoBuffer->release();
1222 mLastVideoBuffer = NULL;
1223 }
1224 mLastVideoBuffer = mVideoBuffer;
1225 mVideoBuffer = NULL;
1226
1227 postVideoEvent_l();
1228}
1229
1230void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1231 if (mVideoEventPending) {
1232 return;
1233 }
1234
1235 mVideoEventPending = true;
1236 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1237}
1238
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001239void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001240 if (mStreamDoneEventPending) {
1241 return;
1242 }
1243 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001244
1245 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001246 mQueue.postEvent(mStreamDoneEvent);
1247}
1248
Andreas Huberb9e63832010-01-26 16:20:10 -08001249void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001250 if (mBufferingEventPending) {
1251 return;
1252 }
1253 mBufferingEventPending = true;
1254 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1255}
1256
Andreas Huber70d10c02010-02-03 11:37:29 -08001257void AwesomePlayer::postCheckAudioStatusEvent_l() {
1258 if (mAudioStatusEventPending) {
1259 return;
1260 }
1261 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001262 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001263}
1264
1265void AwesomePlayer::onCheckAudioStatus() {
1266 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001267 if (!mAudioStatusEventPending) {
1268 // Event was dispatched and while we were blocking on the mutex,
1269 // has already been cancelled.
1270 return;
1271 }
1272
Andreas Huber70d10c02010-02-03 11:37:29 -08001273 mAudioStatusEventPending = false;
1274
1275 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1276 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001277
1278 if (!mSeekNotificationSent) {
1279 notifyListener_l(MEDIA_SEEK_COMPLETE);
1280 mSeekNotificationSent = true;
1281 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001282
1283 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001284 }
1285
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001286 status_t finalStatus;
1287 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001288 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001289 mFlags |= AUDIO_AT_EOS;
1290 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001291 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001292 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001293}
1294
Andreas Huber6be780e2010-02-08 14:40:30 -08001295status_t AwesomePlayer::prepare() {
1296 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001297 return prepare_l();
1298}
Andreas Huber6be780e2010-02-08 14:40:30 -08001299
Andreas Huberffdf4782010-02-09 14:05:43 -08001300status_t AwesomePlayer::prepare_l() {
1301 if (mFlags & PREPARED) {
1302 return OK;
1303 }
1304
1305 if (mFlags & PREPARING) {
1306 return UNKNOWN_ERROR;
1307 }
1308
1309 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001310 status_t err = prepareAsync_l();
1311
1312 if (err != OK) {
1313 return err;
1314 }
1315
Andreas Huberffdf4782010-02-09 14:05:43 -08001316 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001317 mPreparedCondition.wait(mLock);
1318 }
1319
Andreas Huberffdf4782010-02-09 14:05:43 -08001320 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001321}
1322
1323status_t AwesomePlayer::prepareAsync() {
1324 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001325
1326 if (mFlags & PREPARING) {
1327 return UNKNOWN_ERROR; // async prepare already pending
1328 }
1329
1330 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001331 return prepareAsync_l();
1332}
1333
1334status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001335 if (mFlags & PREPARING) {
1336 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001337 }
1338
Andreas Huber406a18b2010-02-18 16:45:13 -08001339 if (!mQueueStarted) {
1340 mQueue.start();
1341 mQueueStarted = true;
1342 }
1343
Andreas Huberffdf4782010-02-09 14:05:43 -08001344 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001345 mAsyncPrepareEvent = new AwesomeEvent(
1346 this, &AwesomePlayer::onPrepareAsyncEvent);
1347
1348 mQueue.postEvent(mAsyncPrepareEvent);
1349
1350 return OK;
1351}
1352
Andreas Huberffdf4782010-02-09 14:05:43 -08001353status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001354 sp<DataSource> dataSource;
1355
1356 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001357 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001358
1359 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001360 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001361 mLock.lock();
1362
1363 if (err != OK) {
1364 mConnectingDataSource.clear();
1365
1366 LOGI("mConnectingDataSource->connect() returned %d", err);
1367 return err;
1368 }
1369
Andreas Huber4d61f602010-06-10 11:17:50 -07001370#if 0
1371 mCachedSource = new NuCachedSource2(
1372 new ThrottledSource(
1373 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1374#else
1375 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1376#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001377 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001378
1379 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001380 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1381 String8 uri("http://");
1382 uri.append(mUri.string() + 11);
1383
Andreas Huber54d09722010-10-12 11:34:37 -07001384 sp<LiveSource> liveSource = new LiveSource(uri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001385
Andreas Huber54d09722010-10-12 11:34:37 -07001386 mCachedSource = new NuCachedSource2(liveSource);
Andreas Huber4d61f602010-06-10 11:17:50 -07001387 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001388
1389 sp<MediaExtractor> extractor =
1390 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001391
Andreas Huber54d09722010-10-12 11:34:37 -07001392 static_cast<MPEG2TSExtractor *>(extractor.get())
1393 ->setLiveSource(liveSource);
1394
Andreas Huber4d61f602010-06-10 11:17:50 -07001395 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001396 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001397 if (mLooper == NULL) {
1398 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001399 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001400 mLooper->start(
1401 false /* runOnCallingThread */,
1402 false /* canCallJava */,
1403 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001404 }
1405
Mike Dodd8741dfa2010-08-12 16:04:35 -07001406 const char *startOfCodecString = &mUri.string()[13];
1407 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1408 if (startOfSlash1 == NULL) {
1409 return BAD_VALUE;
1410 }
1411 const char *startOfWidthString = &startOfSlash1[1];
1412 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1413 if (startOfSlash2 == NULL) {
1414 return BAD_VALUE;
1415 }
1416 const char *startOfHeightString = &startOfSlash2[1];
1417
1418 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1419 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1420 String8 heightString(startOfHeightString);
1421
Andreas Huber57648e42010-08-04 10:14:30 -07001422#if 0
1423 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1424 mLooper->registerHandler(mRTPPusher);
1425
1426 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1427 mLooper->registerHandler(mRTCPPusher);
1428#endif
1429
1430 mRTPSession = new ARTPSession;
1431 mLooper->registerHandler(mRTPSession);
1432
1433#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001434 // My AMR SDP
1435 static const char *raw =
1436 "v=0\r\n"
1437 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1438 "s=QuickTime\r\n"
1439 "t=0 0\r\n"
1440 "a=range:npt=0-315\r\n"
1441 "a=isma-compliance:2,2.0,2\r\n"
1442 "m=audio 5434 RTP/AVP 97\r\n"
1443 "c=IN IP4 127.0.0.1\r\n"
1444 "b=AS:30\r\n"
1445 "a=rtpmap:97 AMR/8000/1\r\n"
1446 "a=fmtp:97 octet-align\r\n";
1447#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001448 String8 sdp;
1449 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001450 "v=0\r\n"
1451 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1452 "s=QuickTime\r\n"
1453 "t=0 0\r\n"
1454 "a=range:npt=0-315\r\n"
1455 "a=isma-compliance:2,2.0,2\r\n"
1456 "m=video 5434 RTP/AVP 97\r\n"
1457 "c=IN IP4 127.0.0.1\r\n"
1458 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001459 "a=rtpmap:97 %s/90000\r\n"
1460 "a=cliprect:0,0,%s,%s\r\n"
1461 "a=framesize:97 %s-%s\r\n",
1462
1463 codecString.string(),
1464 heightString.string(), widthString.string(),
1465 widthString.string(), heightString.string()
1466 );
1467 const char *raw = sdp.string();
1468
Andreas Huber57648e42010-08-04 10:14:30 -07001469#endif
1470
1471 sp<ASessionDescription> desc = new ASessionDescription;
1472 CHECK(desc->setTo(raw, strlen(raw)));
1473
1474 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1475
1476 if (mRTPPusher != NULL) {
1477 mRTPPusher->start();
1478 }
1479
1480 if (mRTCPPusher != NULL) {
1481 mRTCPPusher->start();
1482 }
1483
1484 CHECK_EQ(mRTPSession->countTracks(), 1u);
1485 sp<MediaSource> source = mRTPSession->trackAt(0);
1486
1487#if 0
1488 bool eos;
1489 while (((APacketSource *)source.get())
1490 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1491 usleep(100000ll);
1492 }
1493#endif
1494
1495 const char *mime;
1496 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1497
1498 if (!strncasecmp("video/", mime, 6)) {
1499 setVideoSource(source);
1500 } else {
1501 CHECK(!strncasecmp("audio/", mime, 6));
1502 setAudioSource(source);
1503 }
1504
1505 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1506
1507 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001508 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1509 if (mLooper == NULL) {
1510 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001511 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001512 mLooper->start();
1513 }
1514 mRTSPController = new ARTSPController(mLooper);
1515 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001516
Andreas Huber7a747b82010-06-07 15:19:40 -07001517 LOGI("ARTSPController::connect returned %d", err);
1518
1519 if (err != OK) {
1520 mRTSPController.clear();
1521 return err;
1522 }
1523
1524 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001525 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001526 } else {
1527 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1528 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001529
1530 if (dataSource == NULL) {
1531 return UNKNOWN_ERROR;
1532 }
1533
1534 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1535
1536 if (extractor == NULL) {
1537 return UNKNOWN_ERROR;
1538 }
1539
Andreas Huberffdf4782010-02-09 14:05:43 -08001540 return setDataSource_l(extractor);
1541}
1542
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001543void AwesomePlayer::abortPrepare(status_t err) {
1544 CHECK(err != OK);
1545
1546 if (mIsAsyncPrepare) {
1547 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1548 }
1549
1550 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001551 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001552 mAsyncPrepareEvent = NULL;
1553 mPreparedCondition.broadcast();
1554}
1555
Andreas Huberf71daba2010-03-24 09:24:40 -07001556// static
1557bool AwesomePlayer::ContinuePreparation(void *cookie) {
1558 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1559
1560 return (me->mFlags & PREPARE_CANCELLED) == 0;
1561}
1562
Andreas Huber6be780e2010-02-08 14:40:30 -08001563void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001564 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001565
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001566 if (mFlags & PREPARE_CANCELLED) {
1567 LOGI("prepare was cancelled before doing anything");
1568 abortPrepare(UNKNOWN_ERROR);
1569 return;
1570 }
1571
1572 if (mUri.size() > 0) {
1573 status_t err = finishSetDataSource_l();
1574
1575 if (err != OK) {
1576 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001577 return;
1578 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001579 }
1580
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001581 if (mVideoTrack != NULL && mVideoSource == NULL) {
1582 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001583
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001584 if (err != OK) {
1585 abortPrepare(err);
1586 return;
1587 }
1588 }
1589
1590 if (mAudioTrack != NULL && mAudioSource == NULL) {
1591 status_t err = initAudioDecoder();
1592
1593 if (err != OK) {
1594 abortPrepare(err);
1595 return;
1596 }
1597 }
1598
1599 if (mCachedSource != NULL || mRTSPController != NULL) {
1600 postBufferingEvent_l();
1601 } else {
1602 finishAsyncPrepare_l();
1603 }
1604}
1605
1606void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001607 if (mIsAsyncPrepare) {
1608 if (mVideoWidth < 0 || mVideoHeight < 0) {
1609 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1610 } else {
1611 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1612 }
1613
1614 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001615 }
1616
Andreas Huberffdf4782010-02-09 14:05:43 -08001617 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001618 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001619 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001620 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001621 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001622}
1623
Andreas Huberba7ec912010-02-12 10:42:02 -08001624status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001625 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001626 Mutex::Autolock autoLock(mLock);
1627
1628 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001629 if (mLastVideoBuffer == NULL) {
1630 //go into here if video is suspended again
1631 //after resuming without being played between
1632 //them
1633 SuspensionState *state = mSuspensionState;
1634 mSuspensionState = NULL;
1635 reset_l();
1636 mSuspensionState = state;
1637 return OK;
1638 }
1639
1640 delete mSuspensionState;
1641 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001642 }
1643
Andreas Huberedbb4d82010-03-12 08:59:22 -08001644 if (mFlags & PREPARING) {
1645 mFlags |= PREPARE_CANCELLED;
1646 if (mConnectingDataSource != NULL) {
1647 LOGI("interrupting the connection process");
1648 mConnectingDataSource->disconnect();
1649 }
1650 }
1651
Andreas Huberba7ec912010-02-12 10:42:02 -08001652 while (mFlags & PREPARING) {
1653 mPreparedCondition.wait(mLock);
1654 }
1655
1656 SuspensionState *state = new SuspensionState;
1657 state->mUri = mUri;
1658 state->mUriHeaders = mUriHeaders;
1659 state->mFileSource = mFileSource;
1660
Andreas Huber9fee0b22010-09-03 14:09:21 -07001661 state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001662 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001663
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001664 if (mLastVideoBuffer) {
1665 size_t size = mLastVideoBuffer->range_length();
Andreas Huber1e194162010-10-06 16:43:57 -07001666
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001667 if (size) {
Andreas Huber1e194162010-10-06 16:43:57 -07001668 int32_t unreadable;
1669 if (!mLastVideoBuffer->meta_data()->findInt32(
1670 kKeyIsUnreadable, &unreadable)
1671 || unreadable == 0) {
1672 state->mLastVideoFrameSize = size;
1673 state->mLastVideoFrame = malloc(size);
1674 memcpy(state->mLastVideoFrame,
1675 (const uint8_t *)mLastVideoBuffer->data()
1676 + mLastVideoBuffer->range_offset(),
1677 size);
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001678
Andreas Huber1e194162010-10-06 16:43:57 -07001679 state->mVideoWidth = mVideoWidth;
1680 state->mVideoHeight = mVideoHeight;
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001681
Andreas Huber1e194162010-10-06 16:43:57 -07001682 sp<MetaData> meta = mVideoSource->getFormat();
1683 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1684 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1685 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1686 } else {
1687 LOGV("Unable to save last video frame, we have no access to "
1688 "the decoded video data.");
1689 }
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001690 }
1691 }
1692
Andreas Huberba7ec912010-02-12 10:42:02 -08001693 reset_l();
1694
1695 mSuspensionState = state;
1696
1697 return OK;
1698}
1699
1700status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001701 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001702 Mutex::Autolock autoLock(mLock);
1703
1704 if (mSuspensionState == NULL) {
1705 return INVALID_OPERATION;
1706 }
1707
1708 SuspensionState *state = mSuspensionState;
1709 mSuspensionState = NULL;
1710
1711 status_t err;
1712 if (state->mFileSource != NULL) {
1713 err = setDataSource_l(state->mFileSource);
1714
1715 if (err == OK) {
1716 mFileSource = state->mFileSource;
1717 }
1718 } else {
1719 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1720 }
1721
1722 if (err != OK) {
1723 delete state;
1724 state = NULL;
1725
1726 return err;
1727 }
1728
1729 seekTo_l(state->mPositionUs);
1730
Andreas Huber9fee0b22010-09-03 14:09:21 -07001731 mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001732
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001733 if (state->mLastVideoFrame && mISurface != NULL) {
1734 mVideoRenderer =
1735 new AwesomeLocalRenderer(
1736 true, // previewOnly
1737 "",
1738 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1739 mISurface,
1740 state->mVideoWidth,
1741 state->mVideoHeight,
1742 state->mDecodedWidth,
1743 state->mDecodedHeight);
1744
1745 mVideoRendererIsPreview = true;
1746
1747 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1748 state->mLastVideoFrame, state->mLastVideoFrameSize);
1749 }
1750
Andreas Huberba7ec912010-02-12 10:42:02 -08001751 if (state->mFlags & PLAYING) {
1752 play_l();
1753 }
1754
Gloria Wangb19da8e2010-04-12 17:13:06 -07001755 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001756 state = NULL;
1757
1758 return OK;
1759}
1760
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001761uint32_t AwesomePlayer::flags() const {
1762 return mExtractorFlags;
1763}
1764
Andreas Huber2b359ed2010-09-28 11:56:39 -07001765void AwesomePlayer::postAudioEOS() {
1766 postCheckAudioStatusEvent_l();
1767}
1768
1769void AwesomePlayer::postAudioSeekComplete() {
1770 postCheckAudioStatusEvent_l();
1771}
1772
Andreas Huber27366fc2009-11-20 09:32:46 -08001773} // namespace android
1774