blob: a0cd5c35a63bdda77e79153d4a3f1e80ec1258c9 [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 Huber27366fc2009-11-20 09:32:46 -080029
Andreas Huber57648e42010-08-04 10:14:30 -070030#include "ARTPSession.h"
31#include "APacketSource.h"
32#include "ASessionDescription.h"
33#include "UDPPusher.h"
34
Andreas Hubera67d5382009-12-10 15:32:12 -080035#include <binder/IPCThreadState.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080036#include <media/stagefright/AudioPlayer.h>
37#include <media/stagefright/DataSource.h>
38#include <media/stagefright/FileSource.h>
39#include <media/stagefright/MediaBuffer.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080040#include <media/stagefright/MediaDefs.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080041#include <media/stagefright/MediaExtractor.h>
42#include <media/stagefright/MediaDebug.h>
43#include <media/stagefright/MediaSource.h>
44#include <media/stagefright/MetaData.h>
45#include <media/stagefright/OMXCodec.h>
Andreas Huberc79827a2010-01-05 10:54:55 -080046
Mathias Agopian000479f2010-02-09 17:46:37 -080047#include <surfaceflinger/ISurface.h>
48
Andreas Huber7a747b82010-06-07 15:19:40 -070049#include <media/stagefright/foundation/ALooper.h>
Andreas Huber202348e2010-06-07 14:35:29 -070050
Andreas Huber27366fc2009-11-20 09:32:46 -080051namespace android {
52
53struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080054 AwesomeEvent(
55 AwesomePlayer *player,
56 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080057 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080058 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080059 }
60
61protected:
62 virtual ~AwesomeEvent() {}
63
64 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080065 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080066 }
67
68private:
69 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080070 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080071
72 AwesomeEvent(const AwesomeEvent &);
73 AwesomeEvent &operator=(const AwesomeEvent &);
74};
75
Andreas Huber1314e732009-12-14 14:18:22 -080076struct AwesomeRemoteRenderer : public AwesomeRenderer {
77 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
78 : mTarget(target) {
79 }
80
81 virtual void render(MediaBuffer *buffer) {
82 void *id;
83 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
84 mTarget->render((IOMX::buffer_id)id);
85 }
86 }
87
88private:
89 sp<IOMXRenderer> mTarget;
90
91 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
92 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
93};
94
95struct AwesomeLocalRenderer : public AwesomeRenderer {
96 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -080097 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -080098 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -080099 OMX_COLOR_FORMATTYPE colorFormat,
100 const sp<ISurface> &surface,
101 size_t displayWidth, size_t displayHeight,
102 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800103 : mTarget(NULL),
104 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800105 init(previewOnly, componentName,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800106 colorFormat, surface, displayWidth,
107 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800108 }
109
110 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800111 render((const uint8_t *)buffer->data() + buffer->range_offset(),
112 buffer->range_length());
113 }
114
115 void render(const void *data, size_t size) {
116 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800117 }
118
119protected:
120 virtual ~AwesomeLocalRenderer() {
121 delete mTarget;
122 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800123
124 if (mLibHandle) {
125 dlclose(mLibHandle);
126 mLibHandle = NULL;
127 }
Andreas Huber1314e732009-12-14 14:18:22 -0800128 }
129
130private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800131 VideoRenderer *mTarget;
132 void *mLibHandle;
133
134 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800135 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800136 const char *componentName,
137 OMX_COLOR_FORMATTYPE colorFormat,
138 const sp<ISurface> &surface,
139 size_t displayWidth, size_t displayHeight,
140 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800141
142 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
143 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
144};
145
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800146void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800147 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800148 const char *componentName,
149 OMX_COLOR_FORMATTYPE colorFormat,
150 const sp<ISurface> &surface,
151 size_t displayWidth, size_t displayHeight,
152 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800153 if (!previewOnly) {
154 // We will stick to the vanilla software-color-converting renderer
155 // for "previewOnly" mode, to avoid unneccessarily switching overlays
156 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800157
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800158 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800159
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800160 if (mLibHandle) {
161 typedef VideoRenderer *(*CreateRendererFunc)(
162 const sp<ISurface> &surface,
163 const char *componentName,
164 OMX_COLOR_FORMATTYPE colorFormat,
165 size_t displayWidth, size_t displayHeight,
166 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800167
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800168 CreateRendererFunc func =
169 (CreateRendererFunc)dlsym(
170 mLibHandle,
171 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
172 "OMX_COLOR_FORMATTYPEjjjj");
173
174 if (func) {
175 mTarget =
176 (*func)(surface, componentName, colorFormat,
177 displayWidth, displayHeight,
178 decodedWidth, decodedHeight);
179 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800180 }
181 }
182
183 if (mTarget == NULL) {
184 mTarget = new SoftwareRenderer(
185 colorFormat, surface, displayWidth, displayHeight,
186 decodedWidth, decodedHeight);
187 }
188}
189
Andreas Huber27366fc2009-11-20 09:32:46 -0800190AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800191 : mQueueStarted(false),
192 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800193 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800194 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800195 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700196 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800197 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800198 mVideoBuffer(NULL),
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700199 mRTSPTimeOffset(0),
Andreas Huberba7ec912010-02-12 10:42:02 -0800200 mSuspensionState(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800201 CHECK_EQ(mClient.connect(), OK);
202
203 DataSource::RegisterDefaultSniffers();
204
Andreas Huber6be780e2010-02-08 14:40:30 -0800205 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800206 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800207 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800208 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800209 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800210 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800211
212 mCheckAudioStatusEvent = new AwesomeEvent(
213 this, &AwesomePlayer::onCheckAudioStatus);
214
Andreas Huber70d10c02010-02-03 11:37:29 -0800215 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800216
Andreas Huber27366fc2009-11-20 09:32:46 -0800217 reset();
218}
219
220AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800221 if (mQueueStarted) {
222 mQueue.stop();
223 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800224
225 reset();
226
227 mClient.disconnect();
228}
229
Andreas Huberb9e63832010-01-26 16:20:10 -0800230void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800231 mQueue.cancelEvent(mVideoEvent->eventID());
232 mVideoEventPending = false;
233 mQueue.cancelEvent(mStreamDoneEvent->eventID());
234 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800235 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
236 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800237
238 if (!keepBufferingGoing) {
239 mQueue.cancelEvent(mBufferingEvent->eventID());
240 mBufferingEventPending = false;
241 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800242}
243
Andreas Hubera3f43842010-01-21 10:28:45 -0800244void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800245 Mutex::Autolock autoLock(mLock);
246 mListener = listener;
247}
248
Andreas Huber433c9ac2010-01-27 16:49:05 -0800249status_t AwesomePlayer::setDataSource(
250 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800251 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800252 return setDataSource_l(uri, headers);
253}
Andreas Huber27366fc2009-11-20 09:32:46 -0800254
Andreas Huberba7ec912010-02-12 10:42:02 -0800255status_t AwesomePlayer::setDataSource_l(
256 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800257 reset_l();
258
Andreas Huberffdf4782010-02-09 14:05:43 -0800259 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800260
Andreas Huberffdf4782010-02-09 14:05:43 -0800261 if (headers) {
262 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800263 }
264
Andreas Huberffdf4782010-02-09 14:05:43 -0800265 // The actual work will be done during preparation in the call to
266 // ::finishSetDataSource_l to avoid blocking the calling thread in
267 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800268
Andreas Huberffdf4782010-02-09 14:05:43 -0800269 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800270}
271
272status_t AwesomePlayer::setDataSource(
273 int fd, int64_t offset, int64_t length) {
Andreas Huber202348e2010-06-07 14:35:29 -0700274#if 0
275 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
276 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
277 return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
278 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
279 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
280 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
281 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/mtv/ni_spo_25a_rt74137_clip_syn/hi/prog_index.m3u8");
282#endif
283
Andreas Huber27366fc2009-11-20 09:32:46 -0800284 Mutex::Autolock autoLock(mLock);
285
286 reset_l();
287
Andreas Huberba7ec912010-02-12 10:42:02 -0800288 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800289
Andreas Huberba7ec912010-02-12 10:42:02 -0800290 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800291
292 if (err != OK) {
293 return err;
294 }
295
Andreas Huberba7ec912010-02-12 10:42:02 -0800296 mFileSource = dataSource;
297
298 return setDataSource_l(dataSource);
299}
300
301status_t AwesomePlayer::setDataSource_l(
302 const sp<DataSource> &dataSource) {
303 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800304
305 if (extractor == NULL) {
306 return UNKNOWN_ERROR;
307 }
308
309 return setDataSource_l(extractor);
310}
311
312status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800313 bool haveAudio = false;
314 bool haveVideo = false;
315 for (size_t i = 0; i < extractor->countTracks(); ++i) {
316 sp<MetaData> meta = extractor->getTrackMetaData(i);
317
318 const char *mime;
319 CHECK(meta->findCString(kKeyMIMEType, &mime));
320
321 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800322 setVideoSource(extractor->getTrack(i));
323 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800324 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800325 setAudioSource(extractor->getTrack(i));
326 haveAudio = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800327 }
328
329 if (haveAudio && haveVideo) {
330 break;
331 }
332 }
333
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700334 if (!haveAudio && !haveVideo) {
335 return UNKNOWN_ERROR;
336 }
337
338 mExtractorFlags = extractor->flags();
339
340 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800341}
342
343void AwesomePlayer::reset() {
344 Mutex::Autolock autoLock(mLock);
345 reset_l();
346}
347
348void AwesomePlayer::reset_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -0800349 if (mFlags & PREPARING) {
350 mFlags |= PREPARE_CANCELLED;
351 if (mConnectingDataSource != NULL) {
352 LOGI("interrupting the connection process");
353 mConnectingDataSource->disconnect();
354 }
355 }
356
Andreas Huberffdf4782010-02-09 14:05:43 -0800357 while (mFlags & PREPARING) {
358 mPreparedCondition.wait(mLock);
359 }
360
Andreas Huber27366fc2009-11-20 09:32:46 -0800361 cancelPlayerEvents();
362
Andreas Huber4d61f602010-06-10 11:17:50 -0700363 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800364 mAudioTrack.clear();
365 mVideoTrack.clear();
366
Andreas Huberba7ec912010-02-12 10:42:02 -0800367 // Shutdown audio first, so that the respone to the reset request
368 // appears to happen instantaneously as far as the user is concerned
369 // If we did this later, audio would continue playing while we
370 // shutdown the video-related resources and the player appear to
371 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800372 if (mAudioPlayer == NULL && mAudioSource != NULL) {
373 // If we had an audio player, it would have effectively
374 // taken possession of the audio source and stopped it when
375 // _it_ is stopped. Otherwise this is still our responsibility.
376 mAudioSource->stop();
377 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800378 mAudioSource.clear();
379
Andreas Huberba7ec912010-02-12 10:42:02 -0800380 mTimeSource = NULL;
381
382 delete mAudioPlayer;
383 mAudioPlayer = NULL;
384
Andreas Huber3522b5a52010-01-22 14:36:53 -0800385 mVideoRenderer.clear();
386
Andreas Huber27366fc2009-11-20 09:32:46 -0800387 if (mLastVideoBuffer) {
388 mLastVideoBuffer->release();
389 mLastVideoBuffer = NULL;
390 }
391
392 if (mVideoBuffer) {
393 mVideoBuffer->release();
394 mVideoBuffer = NULL;
395 }
396
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700397 if (mRTSPController != NULL) {
398 mRTSPController->disconnect();
399 mRTSPController.clear();
400 }
401
Andreas Huber57648e42010-08-04 10:14:30 -0700402 mRTPPusher.clear();
403 mRTCPPusher.clear();
404 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700405
Andreas Huber27366fc2009-11-20 09:32:46 -0800406 if (mVideoSource != NULL) {
407 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800408
409 // The following hack is necessary to ensure that the OMX
410 // component is completely released by the time we may try
411 // to instantiate it again.
412 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800413 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800414 while (tmp.promote() != NULL) {
415 usleep(1000);
416 }
417 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800418 }
419
Andreas Huber27366fc2009-11-20 09:32:46 -0800420 mDurationUs = -1;
421 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700422 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800423 mVideoWidth = mVideoHeight = -1;
424 mTimeSourceDeltaUs = 0;
425 mVideoTimeUs = 0;
426
427 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700428 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800429 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800430
Andreas Huberffdf4782010-02-09 14:05:43 -0800431 mUri.setTo("");
432 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800433
434 mFileSource.clear();
435
436 delete mSuspensionState;
437 mSuspensionState = NULL;
Andreas Huber27366fc2009-11-20 09:32:46 -0800438}
439
Andreas Huber6be780e2010-02-08 14:40:30 -0800440void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800441 if (mListener != NULL) {
442 sp<MediaPlayerBase> listener = mListener.promote();
443
444 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800445 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800446 }
447 }
448}
449
Andreas Huberb9e63832010-01-26 16:20:10 -0800450void AwesomePlayer::onBufferingUpdate() {
451 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800452 if (!mBufferingEventPending) {
453 return;
454 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800455 mBufferingEventPending = false;
456
Andreas Huber4d61f602010-06-10 11:17:50 -0700457 if (mCachedSource == NULL) {
458 return;
Andreas Huber252573c2010-03-26 10:17:17 -0700459 }
460
Andreas Huberc23296e2010-08-25 12:31:48 -0700461 bool eos;
462 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
463
Andreas Huber4d61f602010-06-10 11:17:50 -0700464 size_t lowWatermark = 400000;
465 size_t highWatermark = 1000000;
Andreas Huber202348e2010-06-07 14:35:29 -0700466
Andreas Huberc23296e2010-08-25 12:31:48 -0700467 if (eos) {
468 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
469 } else {
470 off_t size;
471 if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
472 int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
Andreas Huber202348e2010-06-07 14:35:29 -0700473
Andreas Huberc23296e2010-08-25 12:31:48 -0700474 size_t cachedSize = mCachedSource->cachedSize();
475 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
Andreas Huberb9e63832010-01-26 16:20:10 -0800476
Andreas Huberc23296e2010-08-25 12:31:48 -0700477 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
478 if (percentage > 100) {
479 percentage = 100;
480 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800481
Andreas Huberc23296e2010-08-25 12:31:48 -0700482 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
Andreas Huberb9e63832010-01-26 16:20:10 -0800483
Andreas Huberc23296e2010-08-25 12:31:48 -0700484 lowWatermark = 2 * bitrate / 8; // 2 secs
485 highWatermark = 10 * bitrate / 8; // 10 secs
486 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800487 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700488
Andreas Huber4d61f602010-06-10 11:17:50 -0700489 if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
490 LOGI("cache is running low (< %d) , pausing.", lowWatermark);
491 mFlags |= CACHE_UNDERRUN;
492 pause_l();
493 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
494 } else if ((mFlags & CACHE_UNDERRUN)
495 && (eos || cachedDataRemaining > highWatermark)) {
496 LOGI("cache has filled up (> %d), resuming.", highWatermark);
497 mFlags &= ~CACHE_UNDERRUN;
498 play_l();
499 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
500 }
501
502 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800503}
504
Andreas Huber27366fc2009-11-20 09:32:46 -0800505void AwesomePlayer::onStreamDone() {
506 // Posted whenever any stream finishes playing.
507
508 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800509 if (!mStreamDoneEventPending) {
510 return;
511 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800512 mStreamDoneEventPending = false;
513
Andreas Huber971305d2010-07-07 13:35:27 -0700514 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
515 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
516
517 notifyListener_l(
518 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
519
520 pause_l();
521
522 mFlags |= AT_EOS;
523 return;
524 }
525
526 const bool allDone =
527 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
528 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
529
530 if (!allDone) {
531 return;
532 }
533
534 if (mFlags & LOOPING) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800535 seekTo_l(0);
536
Andreas Huber7085b6842010-02-03 16:02:02 -0800537 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800538 postVideoEvent_l();
539 }
540 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700541 LOGV("MEDIA_PLAYBACK_COMPLETE");
542 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800543
544 pause_l();
Andreas Huber406a18b2010-02-18 16:45:13 -0800545
546 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800547 }
548}
549
550status_t AwesomePlayer::play() {
551 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700552
553 mFlags &= ~CACHE_UNDERRUN;
554
Andreas Huberba7ec912010-02-12 10:42:02 -0800555 return play_l();
556}
Andreas Huber27366fc2009-11-20 09:32:46 -0800557
Andreas Huberba7ec912010-02-12 10:42:02 -0800558status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800559 if (mFlags & PLAYING) {
560 return OK;
561 }
562
Andreas Huberffdf4782010-02-09 14:05:43 -0800563 if (!(mFlags & PREPARED)) {
564 status_t err = prepare_l();
565
566 if (err != OK) {
567 return err;
568 }
569 }
570
Andreas Huber27366fc2009-11-20 09:32:46 -0800571 mFlags |= PLAYING;
572 mFlags |= FIRST_FRAME;
573
Andreas Huberc1d5c922009-12-10 15:49:04 -0800574 bool deferredAudioSeek = false;
575
Andreas Huber27366fc2009-11-20 09:32:46 -0800576 if (mAudioSource != NULL) {
577 if (mAudioPlayer == NULL) {
578 if (mAudioSink != NULL) {
579 mAudioPlayer = new AudioPlayer(mAudioSink);
Andreas Huber27366fc2009-11-20 09:32:46 -0800580 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800581
582 // We've already started the MediaSource in order to enable
583 // the prefetcher to read its data.
584 status_t err = mAudioPlayer->start(
585 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800586
587 if (err != OK) {
588 delete mAudioPlayer;
589 mAudioPlayer = NULL;
590
591 mFlags &= ~(PLAYING | FIRST_FRAME);
592
593 return err;
594 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800595
Andreas Huber27366fc2009-11-20 09:32:46 -0800596 mTimeSource = mAudioPlayer;
597
Andreas Huberc1d5c922009-12-10 15:49:04 -0800598 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800599
600 mWatchForAudioSeekComplete = false;
601 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800602 }
603 } else {
604 mAudioPlayer->resume();
605 }
Andreas Huber70d10c02010-02-03 11:37:29 -0800606
607 postCheckAudioStatusEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800608 }
609
610 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700611 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800612 }
613
614 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800615 // Kick off video playback
616 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800617 }
618
Andreas Huberc1d5c922009-12-10 15:49:04 -0800619 if (deferredAudioSeek) {
620 // If there was a seek request while we were paused
621 // and we're just starting up again, honor the request now.
622 seekAudioIfNecessary_l();
623 }
624
Andreas Huber406a18b2010-02-18 16:45:13 -0800625 if (mFlags & AT_EOS) {
626 // Legacy behaviour, if a stream finishes playing and then
627 // is started again, we play from the start...
628 seekTo_l(0);
629 }
630
Andreas Huber27366fc2009-11-20 09:32:46 -0800631 return OK;
632}
633
634void AwesomePlayer::initRenderer_l() {
635 if (mISurface != NULL) {
636 sp<MetaData> meta = mVideoSource->getFormat();
637
638 int32_t format;
639 const char *component;
640 int32_t decodedWidth, decodedHeight;
641 CHECK(meta->findInt32(kKeyColorFormat, &format));
642 CHECK(meta->findCString(kKeyDecoderComponent, &component));
643 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
644 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
645
Andreas Hubera67d5382009-12-10 15:32:12 -0800646 mVideoRenderer.clear();
647
648 // Must ensure that mVideoRenderer's destructor is actually executed
649 // before creating a new one.
650 IPCThreadState::self()->flushCommands();
651
Andreas Huber1314e732009-12-14 14:18:22 -0800652 if (!strncmp("OMX.", component, 4)) {
653 // Our OMX codecs allocate buffers on the media_server side
654 // therefore they require a remote IOMXRenderer that knows how
655 // to display them.
656 mVideoRenderer = new AwesomeRemoteRenderer(
657 mClient.interface()->createRenderer(
658 mISurface, component,
659 (OMX_COLOR_FORMATTYPE)format,
660 decodedWidth, decodedHeight,
661 mVideoWidth, mVideoHeight));
662 } else {
663 // Other decoders are instantiated locally and as a consequence
664 // allocate their buffers in local address space.
665 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800666 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800667 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800668 (OMX_COLOR_FORMATTYPE)format,
669 mISurface,
670 mVideoWidth, mVideoHeight,
671 decodedWidth, decodedHeight);
672 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800673 }
674}
675
676status_t AwesomePlayer::pause() {
677 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700678
679 mFlags &= ~CACHE_UNDERRUN;
680
Andreas Huber27366fc2009-11-20 09:32:46 -0800681 return pause_l();
682}
683
684status_t AwesomePlayer::pause_l() {
685 if (!(mFlags & PLAYING)) {
686 return OK;
687 }
688
Andreas Huberb9e63832010-01-26 16:20:10 -0800689 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800690
691 if (mAudioPlayer != NULL) {
692 mAudioPlayer->pause();
693 }
694
695 mFlags &= ~PLAYING;
696
697 return OK;
698}
699
700bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700701 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800702}
703
704void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
705 Mutex::Autolock autoLock(mLock);
706
707 mISurface = isurface;
708}
709
710void AwesomePlayer::setAudioSink(
711 const sp<MediaPlayerBase::AudioSink> &audioSink) {
712 Mutex::Autolock autoLock(mLock);
713
714 mAudioSink = audioSink;
715}
716
717status_t AwesomePlayer::setLooping(bool shouldLoop) {
718 Mutex::Autolock autoLock(mLock);
719
720 mFlags = mFlags & ~LOOPING;
721
722 if (shouldLoop) {
723 mFlags |= LOOPING;
724 }
725
726 return OK;
727}
728
729status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700730 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800731
732 if (mDurationUs < 0) {
733 return UNKNOWN_ERROR;
734 }
735
736 *durationUs = mDurationUs;
737
738 return OK;
739}
740
741status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700742 if (mSeeking) {
743 *positionUs = mSeekTimeUs;
744 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700745 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800746 *positionUs = mVideoTimeUs;
747 } else if (mAudioPlayer != NULL) {
748 *positionUs = mAudioPlayer->getMediaTimeUs();
749 } else {
750 *positionUs = 0;
751 }
752
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700753 if (mRTSPController != NULL) {
754 *positionUs += mRTSPTimeOffset;
755 }
756
Andreas Huber27366fc2009-11-20 09:32:46 -0800757 return OK;
758}
759
760status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700761 if (mExtractorFlags
762 & (MediaExtractor::CAN_SEEK_FORWARD
763 | MediaExtractor::CAN_SEEK_BACKWARD)) {
764 Mutex::Autolock autoLock(mLock);
765 return seekTo_l(timeUs);
766 }
767
768 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800769}
770
771status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700772 if (mRTSPController != NULL) {
773 pause_l();
774 mRTSPController->seek(timeUs);
775 play_l();
776
777 notifyListener_l(MEDIA_SEEK_COMPLETE);
778 mSeekNotificationSent = true;
779 mRTSPTimeOffset = timeUs;
780 return OK;
781 }
782
Andreas Huber4d61f602010-06-10 11:17:50 -0700783 if (mFlags & CACHE_UNDERRUN) {
784 mFlags &= ~CACHE_UNDERRUN;
785 play_l();
786 }
787
Andreas Huber27366fc2009-11-20 09:32:46 -0800788 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700789 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800790 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700791 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -0800792
793 seekAudioIfNecessary_l();
794
Andreas Huber8e2b9412010-03-31 09:40:15 -0700795 if (!(mFlags & PLAYING)) {
796 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
797 " immediately.");
798
799 notifyListener_l(MEDIA_SEEK_COMPLETE);
800 mSeekNotificationSent = true;
801 }
802
Andreas Huber27366fc2009-11-20 09:32:46 -0800803 return OK;
804}
805
806void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800807 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800808 mAudioPlayer->seekTo(mSeekTimeUs);
809
Andreas Huber70d10c02010-02-03 11:37:29 -0800810 mWatchForAudioSeekComplete = true;
811 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700812 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800813 }
814}
815
816status_t AwesomePlayer::getVideoDimensions(
817 int32_t *width, int32_t *height) const {
818 Mutex::Autolock autoLock(mLock);
819
820 if (mVideoWidth < 0 || mVideoHeight < 0) {
821 return UNKNOWN_ERROR;
822 }
823
824 *width = mVideoWidth;
825 *height = mVideoHeight;
826
827 return OK;
828}
829
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800830void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
831 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800832
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800833 mAudioTrack = source;
834}
835
836status_t AwesomePlayer::initAudioDecoder() {
837 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800838
839 const char *mime;
840 CHECK(meta->findCString(kKeyMIMEType, &mime));
841
842 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800843 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800844 } else {
845 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800846 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800847 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800848 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800849 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800850
851 if (mAudioSource != NULL) {
852 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800853 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700854 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800855 if (mDurationUs < 0 || durationUs > mDurationUs) {
856 mDurationUs = durationUs;
857 }
858 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800859
Andreas Huber3c78a1b2010-05-13 09:15:21 -0700860 status_t err = mAudioSource->start();
861
862 if (err != OK) {
863 mAudioSource.clear();
864 return err;
865 }
Andreas Huberd0332ad2010-04-12 16:05:57 -0700866 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
867 // For legacy reasons we're simply going to ignore the absence
868 // of an audio decoder for QCELP instead of aborting playback
869 // altogether.
870 return OK;
871 }
Andreas Huberdc9927d2010-03-08 15:46:13 -0800872
Andreas Huber27366fc2009-11-20 09:32:46 -0800873 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
874}
875
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800876void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
877 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800878
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800879 mVideoTrack = source;
880}
881
882status_t AwesomePlayer::initVideoDecoder() {
Andreas Huber57648e42010-08-04 10:14:30 -0700883 uint32_t flags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800884 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800885 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -0800886 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -0700887 mVideoTrack,
888 NULL, flags);
Andreas Huber27366fc2009-11-20 09:32:46 -0800889
890 if (mVideoSource != NULL) {
891 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800892 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700893 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800894 if (mDurationUs < 0 || durationUs > mDurationUs) {
895 mDurationUs = durationUs;
896 }
897 }
898
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800899 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
900 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -0800901
Andreas Huber1919e5a2010-05-20 10:37:06 -0700902 status_t err = mVideoSource->start();
903
904 if (err != OK) {
905 mVideoSource.clear();
906 return err;
907 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800908 }
909
910 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
911}
912
Andreas Huber6be780e2010-02-08 14:40:30 -0800913void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800914 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800915 if (!mVideoEventPending) {
916 // The event has been cancelled in reset_l() but had already
917 // been scheduled for execution at that time.
918 return;
919 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800920 mVideoEventPending = false;
921
922 if (mSeeking) {
923 if (mLastVideoBuffer) {
924 mLastVideoBuffer->release();
925 mLastVideoBuffer = NULL;
926 }
927
928 if (mVideoBuffer) {
929 mVideoBuffer->release();
930 mVideoBuffer = NULL;
931 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700932
933 if (mCachedSource != NULL && mAudioSource != NULL) {
934 // We're going to seek the video source first, followed by
935 // the audio source.
936 // In order to avoid jumps in the DataSource offset caused by
937 // the audio codec prefetching data from the old locations
938 // while the video codec is already reading data from the new
939 // locations, we'll "pause" the audio source, causing it to
940 // stop reading input data until a subsequent seek.
941
942 if (mAudioPlayer != NULL) {
943 mAudioPlayer->pause();
944 }
945 mAudioSource->pause();
946 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800947 }
948
949 if (!mVideoBuffer) {
950 MediaSource::ReadOptions options;
951 if (mSeeking) {
952 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
953
Andreas Huber6624c9f2010-07-20 15:04:28 -0700954 options.setSeekTo(
955 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -0800956 }
957 for (;;) {
958 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800959 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800960
961 if (err != OK) {
962 CHECK_EQ(mVideoBuffer, NULL);
963
964 if (err == INFO_FORMAT_CHANGED) {
965 LOGV("VideoSource signalled format change.");
966
Andreas Huber7085b6842010-02-03 16:02:02 -0800967 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800968 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -0800969 initRenderer_l();
970 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800971 continue;
972 }
973
Andreas Huber971305d2010-07-07 13:35:27 -0700974 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -0800975 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -0800976 return;
977 }
978
Andreas Hubera67d5382009-12-10 15:32:12 -0800979 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800980 // Some decoders, notably the PV AVC software decoder
981 // return spurious empty buffers that we just want to ignore.
982
Andreas Hubera67d5382009-12-10 15:32:12 -0800983 mVideoBuffer->release();
984 mVideoBuffer = NULL;
985 continue;
986 }
987
Andreas Huber27366fc2009-11-20 09:32:46 -0800988 break;
989 }
990 }
991
992 int64_t timeUs;
993 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
994
Andreas Huber252573c2010-03-26 10:17:17 -0700995 {
996 Mutex::Autolock autoLock(mMiscStateLock);
997 mVideoTimeUs = timeUs;
998 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800999
1000 if (mSeeking) {
1001 if (mAudioPlayer != NULL) {
1002 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
1003
1004 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -07001005 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -08001006 mWatchForAudioSeekComplete = true;
1007 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001008 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001009 // If we're playing video only, report seek complete now,
1010 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -08001011 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -08001012 }
1013
1014 mFlags |= FIRST_FRAME;
1015 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001016 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001017 }
1018
Andreas Huber971305d2010-07-07 13:35:27 -07001019 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1020
Andreas Huber27366fc2009-11-20 09:32:46 -08001021 if (mFlags & FIRST_FRAME) {
1022 mFlags &= ~FIRST_FRAME;
1023
Andreas Huber971305d2010-07-07 13:35:27 -07001024 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001025 }
1026
1027 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001028 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001029 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1030 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1031 }
1032
Andreas Huber971305d2010-07-07 13:35:27 -07001033 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001034
1035 int64_t latenessUs = nowUs - timeUs;
1036
Andreas Huberf88f8442010-08-10 11:18:36 -07001037 if (mRTPSession != NULL) {
1038 // We'll completely ignore timestamps for gtalk videochat
1039 // and we'll play incoming video as fast as we get it.
1040 latenessUs = 0;
1041 }
1042
Andreas Huber24b0a952009-11-23 14:02:00 -08001043 if (latenessUs > 40000) {
1044 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001045 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001046
1047 mVideoBuffer->release();
1048 mVideoBuffer = NULL;
1049
1050 postVideoEvent_l();
1051 return;
1052 }
1053
1054 if (latenessUs < -10000) {
1055 // We're more than 10ms early.
1056
1057 postVideoEvent_l(10000);
1058 return;
1059 }
1060
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001061 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1062 mVideoRendererIsPreview = false;
1063
Andreas Huber7085b6842010-02-03 16:02:02 -08001064 initRenderer_l();
1065 }
1066
1067 if (mVideoRenderer != NULL) {
1068 mVideoRenderer->render(mVideoBuffer);
1069 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001070
1071 if (mLastVideoBuffer) {
1072 mLastVideoBuffer->release();
1073 mLastVideoBuffer = NULL;
1074 }
1075 mLastVideoBuffer = mVideoBuffer;
1076 mVideoBuffer = NULL;
1077
1078 postVideoEvent_l();
1079}
1080
1081void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1082 if (mVideoEventPending) {
1083 return;
1084 }
1085
1086 mVideoEventPending = true;
1087 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1088}
1089
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001090void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001091 if (mStreamDoneEventPending) {
1092 return;
1093 }
1094 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001095
1096 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001097 mQueue.postEvent(mStreamDoneEvent);
1098}
1099
Andreas Huberb9e63832010-01-26 16:20:10 -08001100void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001101 if (mBufferingEventPending) {
1102 return;
1103 }
1104 mBufferingEventPending = true;
1105 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1106}
1107
Andreas Huber70d10c02010-02-03 11:37:29 -08001108void AwesomePlayer::postCheckAudioStatusEvent_l() {
1109 if (mAudioStatusEventPending) {
1110 return;
1111 }
1112 mAudioStatusEventPending = true;
1113 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
1114}
1115
1116void AwesomePlayer::onCheckAudioStatus() {
1117 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001118 if (!mAudioStatusEventPending) {
1119 // Event was dispatched and while we were blocking on the mutex,
1120 // has already been cancelled.
1121 return;
1122 }
1123
Andreas Huber70d10c02010-02-03 11:37:29 -08001124 mAudioStatusEventPending = false;
1125
1126 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1127 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001128
1129 if (!mSeekNotificationSent) {
1130 notifyListener_l(MEDIA_SEEK_COMPLETE);
1131 mSeekNotificationSent = true;
1132 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001133
1134 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001135 }
1136
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001137 status_t finalStatus;
1138 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001139 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001140 mFlags |= AUDIO_AT_EOS;
1141 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001142 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001143 }
1144
1145 postCheckAudioStatusEvent_l();
1146}
1147
Andreas Huber6be780e2010-02-08 14:40:30 -08001148status_t AwesomePlayer::prepare() {
1149 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001150 return prepare_l();
1151}
Andreas Huber6be780e2010-02-08 14:40:30 -08001152
Andreas Huberffdf4782010-02-09 14:05:43 -08001153status_t AwesomePlayer::prepare_l() {
1154 if (mFlags & PREPARED) {
1155 return OK;
1156 }
1157
1158 if (mFlags & PREPARING) {
1159 return UNKNOWN_ERROR;
1160 }
1161
1162 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001163 status_t err = prepareAsync_l();
1164
1165 if (err != OK) {
1166 return err;
1167 }
1168
Andreas Huberffdf4782010-02-09 14:05:43 -08001169 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001170 mPreparedCondition.wait(mLock);
1171 }
1172
Andreas Huberffdf4782010-02-09 14:05:43 -08001173 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001174}
1175
1176status_t AwesomePlayer::prepareAsync() {
1177 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001178
1179 if (mFlags & PREPARING) {
1180 return UNKNOWN_ERROR; // async prepare already pending
1181 }
1182
1183 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001184 return prepareAsync_l();
1185}
1186
1187status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001188 if (mFlags & PREPARING) {
1189 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001190 }
1191
Andreas Huber406a18b2010-02-18 16:45:13 -08001192 if (!mQueueStarted) {
1193 mQueue.start();
1194 mQueueStarted = true;
1195 }
1196
Andreas Huberffdf4782010-02-09 14:05:43 -08001197 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001198 mAsyncPrepareEvent = new AwesomeEvent(
1199 this, &AwesomePlayer::onPrepareAsyncEvent);
1200
1201 mQueue.postEvent(mAsyncPrepareEvent);
1202
1203 return OK;
1204}
1205
Andreas Huberffdf4782010-02-09 14:05:43 -08001206status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001207 sp<DataSource> dataSource;
1208
1209 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001210 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001211
1212 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001213 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001214 mLock.lock();
1215
1216 if (err != OK) {
1217 mConnectingDataSource.clear();
1218
1219 LOGI("mConnectingDataSource->connect() returned %d", err);
1220 return err;
1221 }
1222
Andreas Huber4d61f602010-06-10 11:17:50 -07001223#if 0
1224 mCachedSource = new NuCachedSource2(
1225 new ThrottledSource(
1226 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1227#else
1228 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1229#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001230 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001231
1232 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001233 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1234 String8 uri("http://");
1235 uri.append(mUri.string() + 11);
1236
1237 dataSource = new LiveSource(uri.string());
1238
Andreas Huber4d61f602010-06-10 11:17:50 -07001239 mCachedSource = new NuCachedSource2(dataSource);
1240 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001241
1242 sp<MediaExtractor> extractor =
1243 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001244
1245 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001246 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001247 if (mLooper == NULL) {
1248 mLooper = new ALooper;
Andreas Huber3eaa3002010-08-05 09:22:25 -07001249 mLooper->start(
1250 false /* runOnCallingThread */,
1251 false /* canCallJava */,
1252 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001253 }
1254
Mike Dodd8741dfa2010-08-12 16:04:35 -07001255 const char *startOfCodecString = &mUri.string()[13];
1256 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1257 if (startOfSlash1 == NULL) {
1258 return BAD_VALUE;
1259 }
1260 const char *startOfWidthString = &startOfSlash1[1];
1261 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1262 if (startOfSlash2 == NULL) {
1263 return BAD_VALUE;
1264 }
1265 const char *startOfHeightString = &startOfSlash2[1];
1266
1267 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1268 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1269 String8 heightString(startOfHeightString);
1270
Andreas Huber57648e42010-08-04 10:14:30 -07001271#if 0
1272 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1273 mLooper->registerHandler(mRTPPusher);
1274
1275 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1276 mLooper->registerHandler(mRTCPPusher);
1277#endif
1278
1279 mRTPSession = new ARTPSession;
1280 mLooper->registerHandler(mRTPSession);
1281
1282#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001283 // My AMR SDP
1284 static const char *raw =
1285 "v=0\r\n"
1286 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1287 "s=QuickTime\r\n"
1288 "t=0 0\r\n"
1289 "a=range:npt=0-315\r\n"
1290 "a=isma-compliance:2,2.0,2\r\n"
1291 "m=audio 5434 RTP/AVP 97\r\n"
1292 "c=IN IP4 127.0.0.1\r\n"
1293 "b=AS:30\r\n"
1294 "a=rtpmap:97 AMR/8000/1\r\n"
1295 "a=fmtp:97 octet-align\r\n";
1296#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001297 String8 sdp;
1298 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001299 "v=0\r\n"
1300 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1301 "s=QuickTime\r\n"
1302 "t=0 0\r\n"
1303 "a=range:npt=0-315\r\n"
1304 "a=isma-compliance:2,2.0,2\r\n"
1305 "m=video 5434 RTP/AVP 97\r\n"
1306 "c=IN IP4 127.0.0.1\r\n"
1307 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001308 "a=rtpmap:97 %s/90000\r\n"
1309 "a=cliprect:0,0,%s,%s\r\n"
1310 "a=framesize:97 %s-%s\r\n",
1311
1312 codecString.string(),
1313 heightString.string(), widthString.string(),
1314 widthString.string(), heightString.string()
1315 );
1316 const char *raw = sdp.string();
1317
Andreas Huber57648e42010-08-04 10:14:30 -07001318#endif
1319
1320 sp<ASessionDescription> desc = new ASessionDescription;
1321 CHECK(desc->setTo(raw, strlen(raw)));
1322
1323 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1324
1325 if (mRTPPusher != NULL) {
1326 mRTPPusher->start();
1327 }
1328
1329 if (mRTCPPusher != NULL) {
1330 mRTCPPusher->start();
1331 }
1332
1333 CHECK_EQ(mRTPSession->countTracks(), 1u);
1334 sp<MediaSource> source = mRTPSession->trackAt(0);
1335
1336#if 0
1337 bool eos;
1338 while (((APacketSource *)source.get())
1339 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1340 usleep(100000ll);
1341 }
1342#endif
1343
1344 const char *mime;
1345 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1346
1347 if (!strncasecmp("video/", mime, 6)) {
1348 setVideoSource(source);
1349 } else {
1350 CHECK(!strncasecmp("audio/", mime, 6));
1351 setAudioSource(source);
1352 }
1353
1354 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1355
1356 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001357 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1358 if (mLooper == NULL) {
1359 mLooper = new ALooper;
1360 mLooper->start();
1361 }
1362 mRTSPController = new ARTSPController(mLooper);
1363 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001364
Andreas Huber7a747b82010-06-07 15:19:40 -07001365 LOGI("ARTSPController::connect returned %d", err);
1366
1367 if (err != OK) {
1368 mRTSPController.clear();
1369 return err;
1370 }
1371
1372 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001373 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001374 } else {
1375 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1376 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001377
1378 if (dataSource == NULL) {
1379 return UNKNOWN_ERROR;
1380 }
1381
1382 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1383
1384 if (extractor == NULL) {
1385 return UNKNOWN_ERROR;
1386 }
1387
Andreas Huberffdf4782010-02-09 14:05:43 -08001388 return setDataSource_l(extractor);
1389}
1390
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001391void AwesomePlayer::abortPrepare(status_t err) {
1392 CHECK(err != OK);
1393
1394 if (mIsAsyncPrepare) {
1395 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1396 }
1397
1398 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001399 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001400 mAsyncPrepareEvent = NULL;
1401 mPreparedCondition.broadcast();
1402}
1403
Andreas Huberf71daba2010-03-24 09:24:40 -07001404// static
1405bool AwesomePlayer::ContinuePreparation(void *cookie) {
1406 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1407
1408 return (me->mFlags & PREPARE_CANCELLED) == 0;
1409}
1410
Andreas Huber6be780e2010-02-08 14:40:30 -08001411void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001412 {
1413 Mutex::Autolock autoLock(mLock);
1414
Andreas Huberedbb4d82010-03-12 08:59:22 -08001415 if (mFlags & PREPARE_CANCELLED) {
1416 LOGI("prepare was cancelled before doing anything");
1417 abortPrepare(UNKNOWN_ERROR);
1418 return;
1419 }
1420
Andreas Huberffdf4782010-02-09 14:05:43 -08001421 if (mUri.size() > 0) {
1422 status_t err = finishSetDataSource_l();
1423
1424 if (err != OK) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001425 abortPrepare(err);
Andreas Huberffdf4782010-02-09 14:05:43 -08001426 return;
1427 }
1428 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001429
Andreas Huber55864df72010-03-08 12:28:22 -08001430 if (mVideoTrack != NULL && mVideoSource == NULL) {
1431 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001432
Andreas Huber55864df72010-03-08 12:28:22 -08001433 if (err != OK) {
1434 abortPrepare(err);
1435 return;
1436 }
1437 }
1438
1439 if (mAudioTrack != NULL && mAudioSource == NULL) {
1440 status_t err = initAudioDecoder();
1441
1442 if (err != OK) {
1443 abortPrepare(err);
1444 return;
1445 }
1446 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001447 }
1448
1449 Mutex::Autolock autoLock(mLock);
1450
Andreas Huberffdf4782010-02-09 14:05:43 -08001451 if (mIsAsyncPrepare) {
1452 if (mVideoWidth < 0 || mVideoHeight < 0) {
1453 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1454 } else {
1455 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1456 }
1457
1458 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001459 }
1460
Andreas Huberffdf4782010-02-09 14:05:43 -08001461 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001462 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001463 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001464 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001465 mPreparedCondition.broadcast();
Andreas Huber040301c2010-04-12 09:41:12 -07001466
1467 postBufferingEvent_l();
Andreas Huber6be780e2010-02-08 14:40:30 -08001468}
1469
Andreas Huberba7ec912010-02-12 10:42:02 -08001470status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001471 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001472 Mutex::Autolock autoLock(mLock);
1473
1474 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001475 if (mLastVideoBuffer == NULL) {
1476 //go into here if video is suspended again
1477 //after resuming without being played between
1478 //them
1479 SuspensionState *state = mSuspensionState;
1480 mSuspensionState = NULL;
1481 reset_l();
1482 mSuspensionState = state;
1483 return OK;
1484 }
1485
1486 delete mSuspensionState;
1487 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001488 }
1489
Andreas Huberedbb4d82010-03-12 08:59:22 -08001490 if (mFlags & PREPARING) {
1491 mFlags |= PREPARE_CANCELLED;
1492 if (mConnectingDataSource != NULL) {
1493 LOGI("interrupting the connection process");
1494 mConnectingDataSource->disconnect();
1495 }
1496 }
1497
Andreas Huberba7ec912010-02-12 10:42:02 -08001498 while (mFlags & PREPARING) {
1499 mPreparedCondition.wait(mLock);
1500 }
1501
1502 SuspensionState *state = new SuspensionState;
1503 state->mUri = mUri;
1504 state->mUriHeaders = mUriHeaders;
1505 state->mFileSource = mFileSource;
1506
Andreas Huber406a18b2010-02-18 16:45:13 -08001507 state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001508 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001509
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001510 if (mLastVideoBuffer) {
1511 size_t size = mLastVideoBuffer->range_length();
1512 if (size) {
1513 state->mLastVideoFrameSize = size;
1514 state->mLastVideoFrame = malloc(size);
1515 memcpy(state->mLastVideoFrame,
1516 (const uint8_t *)mLastVideoBuffer->data()
1517 + mLastVideoBuffer->range_offset(),
1518 size);
1519
1520 state->mVideoWidth = mVideoWidth;
1521 state->mVideoHeight = mVideoHeight;
1522
1523 sp<MetaData> meta = mVideoSource->getFormat();
1524 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1525 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1526 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1527 }
1528 }
1529
Andreas Huberba7ec912010-02-12 10:42:02 -08001530 reset_l();
1531
1532 mSuspensionState = state;
1533
1534 return OK;
1535}
1536
1537status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001538 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001539 Mutex::Autolock autoLock(mLock);
1540
1541 if (mSuspensionState == NULL) {
1542 return INVALID_OPERATION;
1543 }
1544
1545 SuspensionState *state = mSuspensionState;
1546 mSuspensionState = NULL;
1547
1548 status_t err;
1549 if (state->mFileSource != NULL) {
1550 err = setDataSource_l(state->mFileSource);
1551
1552 if (err == OK) {
1553 mFileSource = state->mFileSource;
1554 }
1555 } else {
1556 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1557 }
1558
1559 if (err != OK) {
1560 delete state;
1561 state = NULL;
1562
1563 return err;
1564 }
1565
1566 seekTo_l(state->mPositionUs);
1567
Andreas Huber406a18b2010-02-18 16:45:13 -08001568 mFlags = state->mFlags & (LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001569
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001570 if (state->mLastVideoFrame && mISurface != NULL) {
1571 mVideoRenderer =
1572 new AwesomeLocalRenderer(
1573 true, // previewOnly
1574 "",
1575 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1576 mISurface,
1577 state->mVideoWidth,
1578 state->mVideoHeight,
1579 state->mDecodedWidth,
1580 state->mDecodedHeight);
1581
1582 mVideoRendererIsPreview = true;
1583
1584 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1585 state->mLastVideoFrame, state->mLastVideoFrameSize);
1586 }
1587
Andreas Huberba7ec912010-02-12 10:42:02 -08001588 if (state->mFlags & PLAYING) {
1589 play_l();
1590 }
1591
Gloria Wangb19da8e2010-04-12 17:13:06 -07001592 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001593 state = NULL;
1594
1595 return OK;
1596}
1597
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001598uint32_t AwesomePlayer::flags() const {
1599 return mExtractorFlags;
1600}
1601
Andreas Huber27366fc2009-11-20 09:32:46 -08001602} // namespace android
1603