blob: 7daac96b0a48d3aeba789fce4f99ed8384cd09dd [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),
199 mSuspensionState(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800200 CHECK_EQ(mClient.connect(), OK);
201
202 DataSource::RegisterDefaultSniffers();
203
Andreas Huber6be780e2010-02-08 14:40:30 -0800204 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800205 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800206 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800207 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800208 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800209 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800210
211 mCheckAudioStatusEvent = new AwesomeEvent(
212 this, &AwesomePlayer::onCheckAudioStatus);
213
Andreas Huber70d10c02010-02-03 11:37:29 -0800214 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800215
Andreas Huber27366fc2009-11-20 09:32:46 -0800216 reset();
217}
218
219AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800220 if (mQueueStarted) {
221 mQueue.stop();
222 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800223
224 reset();
225
226 mClient.disconnect();
227}
228
Andreas Huberb9e63832010-01-26 16:20:10 -0800229void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800230 mQueue.cancelEvent(mVideoEvent->eventID());
231 mVideoEventPending = false;
232 mQueue.cancelEvent(mStreamDoneEvent->eventID());
233 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800234 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
235 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800236
237 if (!keepBufferingGoing) {
238 mQueue.cancelEvent(mBufferingEvent->eventID());
239 mBufferingEventPending = false;
240 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800241}
242
Andreas Hubera3f43842010-01-21 10:28:45 -0800243void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800244 Mutex::Autolock autoLock(mLock);
245 mListener = listener;
246}
247
Andreas Huber433c9ac2010-01-27 16:49:05 -0800248status_t AwesomePlayer::setDataSource(
249 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800250 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800251 return setDataSource_l(uri, headers);
252}
Andreas Huber27366fc2009-11-20 09:32:46 -0800253
Andreas Huberba7ec912010-02-12 10:42:02 -0800254status_t AwesomePlayer::setDataSource_l(
255 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800256 reset_l();
257
Andreas Huberffdf4782010-02-09 14:05:43 -0800258 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800259
Andreas Huberffdf4782010-02-09 14:05:43 -0800260 if (headers) {
261 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800262 }
263
Andreas Huberffdf4782010-02-09 14:05:43 -0800264 // The actual work will be done during preparation in the call to
265 // ::finishSetDataSource_l to avoid blocking the calling thread in
266 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800267
Andreas Huberffdf4782010-02-09 14:05:43 -0800268 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800269}
270
271status_t AwesomePlayer::setDataSource(
272 int fd, int64_t offset, int64_t length) {
Andreas Huber202348e2010-06-07 14:35:29 -0700273#if 0
274 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
275 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
276 return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
277 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
278 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
279 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
280 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/mtv/ni_spo_25a_rt74137_clip_syn/hi/prog_index.m3u8");
281#endif
282
Andreas Huber27366fc2009-11-20 09:32:46 -0800283 Mutex::Autolock autoLock(mLock);
284
285 reset_l();
286
Andreas Huberba7ec912010-02-12 10:42:02 -0800287 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800288
Andreas Huberba7ec912010-02-12 10:42:02 -0800289 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800290
291 if (err != OK) {
292 return err;
293 }
294
Andreas Huberba7ec912010-02-12 10:42:02 -0800295 mFileSource = dataSource;
296
297 return setDataSource_l(dataSource);
298}
299
300status_t AwesomePlayer::setDataSource_l(
301 const sp<DataSource> &dataSource) {
302 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800303
304 if (extractor == NULL) {
305 return UNKNOWN_ERROR;
306 }
307
308 return setDataSource_l(extractor);
309}
310
311status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800312 bool haveAudio = false;
313 bool haveVideo = false;
314 for (size_t i = 0; i < extractor->countTracks(); ++i) {
315 sp<MetaData> meta = extractor->getTrackMetaData(i);
316
317 const char *mime;
318 CHECK(meta->findCString(kKeyMIMEType, &mime));
319
320 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800321 setVideoSource(extractor->getTrack(i));
322 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800323 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800324 setAudioSource(extractor->getTrack(i));
325 haveAudio = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800326 }
327
328 if (haveAudio && haveVideo) {
329 break;
330 }
331 }
332
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700333 if (!haveAudio && !haveVideo) {
334 return UNKNOWN_ERROR;
335 }
336
337 mExtractorFlags = extractor->flags();
338
339 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800340}
341
342void AwesomePlayer::reset() {
343 Mutex::Autolock autoLock(mLock);
344 reset_l();
345}
346
347void AwesomePlayer::reset_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -0800348 if (mFlags & PREPARING) {
349 mFlags |= PREPARE_CANCELLED;
350 if (mConnectingDataSource != NULL) {
351 LOGI("interrupting the connection process");
352 mConnectingDataSource->disconnect();
353 }
354 }
355
Andreas Huberffdf4782010-02-09 14:05:43 -0800356 while (mFlags & PREPARING) {
357 mPreparedCondition.wait(mLock);
358 }
359
Andreas Huber27366fc2009-11-20 09:32:46 -0800360 cancelPlayerEvents();
361
Andreas Huber4d61f602010-06-10 11:17:50 -0700362 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800363 mAudioTrack.clear();
364 mVideoTrack.clear();
365
Andreas Huberba7ec912010-02-12 10:42:02 -0800366 // Shutdown audio first, so that the respone to the reset request
367 // appears to happen instantaneously as far as the user is concerned
368 // If we did this later, audio would continue playing while we
369 // shutdown the video-related resources and the player appear to
370 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800371 if (mAudioPlayer == NULL && mAudioSource != NULL) {
372 // If we had an audio player, it would have effectively
373 // taken possession of the audio source and stopped it when
374 // _it_ is stopped. Otherwise this is still our responsibility.
375 mAudioSource->stop();
376 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800377 mAudioSource.clear();
378
Andreas Huberba7ec912010-02-12 10:42:02 -0800379 mTimeSource = NULL;
380
381 delete mAudioPlayer;
382 mAudioPlayer = NULL;
383
Andreas Huber3522b5a52010-01-22 14:36:53 -0800384 mVideoRenderer.clear();
385
Andreas Huber27366fc2009-11-20 09:32:46 -0800386 if (mLastVideoBuffer) {
387 mLastVideoBuffer->release();
388 mLastVideoBuffer = NULL;
389 }
390
391 if (mVideoBuffer) {
392 mVideoBuffer->release();
393 mVideoBuffer = NULL;
394 }
395
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700396 if (mRTSPController != NULL) {
397 mRTSPController->disconnect();
398 mRTSPController.clear();
399 }
400
Andreas Huber57648e42010-08-04 10:14:30 -0700401 mRTPPusher.clear();
402 mRTCPPusher.clear();
403 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700404
Andreas Huber27366fc2009-11-20 09:32:46 -0800405 if (mVideoSource != NULL) {
406 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800407
408 // The following hack is necessary to ensure that the OMX
409 // component is completely released by the time we may try
410 // to instantiate it again.
411 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800412 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800413 while (tmp.promote() != NULL) {
414 usleep(1000);
415 }
416 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800417 }
418
Andreas Huber27366fc2009-11-20 09:32:46 -0800419 mDurationUs = -1;
420 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700421 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800422 mVideoWidth = mVideoHeight = -1;
423 mTimeSourceDeltaUs = 0;
424 mVideoTimeUs = 0;
425
426 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700427 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800428 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800429
Andreas Huberffdf4782010-02-09 14:05:43 -0800430 mUri.setTo("");
431 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800432
433 mFileSource.clear();
434
435 delete mSuspensionState;
436 mSuspensionState = NULL;
Andreas Huber27366fc2009-11-20 09:32:46 -0800437}
438
Andreas Huber6be780e2010-02-08 14:40:30 -0800439void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800440 if (mListener != NULL) {
441 sp<MediaPlayerBase> listener = mListener.promote();
442
443 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800444 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800445 }
446 }
447}
448
Andreas Huberb9e63832010-01-26 16:20:10 -0800449void AwesomePlayer::onBufferingUpdate() {
450 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800451 if (!mBufferingEventPending) {
452 return;
453 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800454 mBufferingEventPending = false;
455
Andreas Huber4d61f602010-06-10 11:17:50 -0700456 if (mCachedSource == NULL) {
457 return;
Andreas Huber252573c2010-03-26 10:17:17 -0700458 }
459
Andreas Huberc23296e2010-08-25 12:31:48 -0700460 bool eos;
461 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
462
Andreas Huber4d61f602010-06-10 11:17:50 -0700463 size_t lowWatermark = 400000;
464 size_t highWatermark = 1000000;
Andreas Huber202348e2010-06-07 14:35:29 -0700465
Andreas Huberc23296e2010-08-25 12:31:48 -0700466 if (eos) {
467 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
468 } else {
469 off_t size;
470 if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
471 int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
Andreas Huber202348e2010-06-07 14:35:29 -0700472
Andreas Huberc23296e2010-08-25 12:31:48 -0700473 size_t cachedSize = mCachedSource->cachedSize();
474 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
Andreas Huberb9e63832010-01-26 16:20:10 -0800475
Andreas Huberc23296e2010-08-25 12:31:48 -0700476 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
477 if (percentage > 100) {
478 percentage = 100;
479 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800480
Andreas Huberc23296e2010-08-25 12:31:48 -0700481 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
Andreas Huberb9e63832010-01-26 16:20:10 -0800482
Andreas Huberc23296e2010-08-25 12:31:48 -0700483 lowWatermark = 2 * bitrate / 8; // 2 secs
484 highWatermark = 10 * bitrate / 8; // 10 secs
485 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800486 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700487
Andreas Huber4d61f602010-06-10 11:17:50 -0700488 if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
489 LOGI("cache is running low (< %d) , pausing.", lowWatermark);
490 mFlags |= CACHE_UNDERRUN;
491 pause_l();
492 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
493 } else if ((mFlags & CACHE_UNDERRUN)
494 && (eos || cachedDataRemaining > highWatermark)) {
495 LOGI("cache has filled up (> %d), resuming.", highWatermark);
496 mFlags &= ~CACHE_UNDERRUN;
497 play_l();
498 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
499 }
500
501 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800502}
503
Andreas Huber27366fc2009-11-20 09:32:46 -0800504void AwesomePlayer::onStreamDone() {
505 // Posted whenever any stream finishes playing.
506
507 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800508 if (!mStreamDoneEventPending) {
509 return;
510 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800511 mStreamDoneEventPending = false;
512
Andreas Huber971305d2010-07-07 13:35:27 -0700513 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
514 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
515
516 notifyListener_l(
517 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
518
519 pause_l();
520
521 mFlags |= AT_EOS;
522 return;
523 }
524
525 const bool allDone =
526 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
527 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
528
529 if (!allDone) {
530 return;
531 }
532
533 if (mFlags & LOOPING) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800534 seekTo_l(0);
535
Andreas Huber7085b6842010-02-03 16:02:02 -0800536 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800537 postVideoEvent_l();
538 }
539 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700540 LOGV("MEDIA_PLAYBACK_COMPLETE");
541 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800542
543 pause_l();
Andreas Huber406a18b2010-02-18 16:45:13 -0800544
545 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800546 }
547}
548
549status_t AwesomePlayer::play() {
550 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700551
552 mFlags &= ~CACHE_UNDERRUN;
553
Andreas Huberba7ec912010-02-12 10:42:02 -0800554 return play_l();
555}
Andreas Huber27366fc2009-11-20 09:32:46 -0800556
Andreas Huberba7ec912010-02-12 10:42:02 -0800557status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800558 if (mFlags & PLAYING) {
559 return OK;
560 }
561
Andreas Huberffdf4782010-02-09 14:05:43 -0800562 if (!(mFlags & PREPARED)) {
563 status_t err = prepare_l();
564
565 if (err != OK) {
566 return err;
567 }
568 }
569
Andreas Huber27366fc2009-11-20 09:32:46 -0800570 mFlags |= PLAYING;
571 mFlags |= FIRST_FRAME;
572
Andreas Huberc1d5c922009-12-10 15:49:04 -0800573 bool deferredAudioSeek = false;
574
Andreas Huber27366fc2009-11-20 09:32:46 -0800575 if (mAudioSource != NULL) {
576 if (mAudioPlayer == NULL) {
577 if (mAudioSink != NULL) {
578 mAudioPlayer = new AudioPlayer(mAudioSink);
Andreas Huber27366fc2009-11-20 09:32:46 -0800579 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800580
581 // We've already started the MediaSource in order to enable
582 // the prefetcher to read its data.
583 status_t err = mAudioPlayer->start(
584 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800585
586 if (err != OK) {
587 delete mAudioPlayer;
588 mAudioPlayer = NULL;
589
590 mFlags &= ~(PLAYING | FIRST_FRAME);
591
592 return err;
593 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800594
Andreas Huber27366fc2009-11-20 09:32:46 -0800595 mTimeSource = mAudioPlayer;
596
Andreas Huberc1d5c922009-12-10 15:49:04 -0800597 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800598
599 mWatchForAudioSeekComplete = false;
600 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800601 }
602 } else {
603 mAudioPlayer->resume();
604 }
Andreas Huber70d10c02010-02-03 11:37:29 -0800605
606 postCheckAudioStatusEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800607 }
608
609 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700610 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800611 }
612
613 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800614 // Kick off video playback
615 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800616 }
617
Andreas Huberc1d5c922009-12-10 15:49:04 -0800618 if (deferredAudioSeek) {
619 // If there was a seek request while we were paused
620 // and we're just starting up again, honor the request now.
621 seekAudioIfNecessary_l();
622 }
623
Andreas Huber406a18b2010-02-18 16:45:13 -0800624 if (mFlags & AT_EOS) {
625 // Legacy behaviour, if a stream finishes playing and then
626 // is started again, we play from the start...
627 seekTo_l(0);
628 }
629
Andreas Huber27366fc2009-11-20 09:32:46 -0800630 return OK;
631}
632
633void AwesomePlayer::initRenderer_l() {
634 if (mISurface != NULL) {
635 sp<MetaData> meta = mVideoSource->getFormat();
636
637 int32_t format;
638 const char *component;
639 int32_t decodedWidth, decodedHeight;
640 CHECK(meta->findInt32(kKeyColorFormat, &format));
641 CHECK(meta->findCString(kKeyDecoderComponent, &component));
642 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
643 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
644
Andreas Hubera67d5382009-12-10 15:32:12 -0800645 mVideoRenderer.clear();
646
647 // Must ensure that mVideoRenderer's destructor is actually executed
648 // before creating a new one.
649 IPCThreadState::self()->flushCommands();
650
Andreas Huber1314e732009-12-14 14:18:22 -0800651 if (!strncmp("OMX.", component, 4)) {
652 // Our OMX codecs allocate buffers on the media_server side
653 // therefore they require a remote IOMXRenderer that knows how
654 // to display them.
655 mVideoRenderer = new AwesomeRemoteRenderer(
656 mClient.interface()->createRenderer(
657 mISurface, component,
658 (OMX_COLOR_FORMATTYPE)format,
659 decodedWidth, decodedHeight,
660 mVideoWidth, mVideoHeight));
661 } else {
662 // Other decoders are instantiated locally and as a consequence
663 // allocate their buffers in local address space.
664 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800665 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800666 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800667 (OMX_COLOR_FORMATTYPE)format,
668 mISurface,
669 mVideoWidth, mVideoHeight,
670 decodedWidth, decodedHeight);
671 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800672 }
673}
674
675status_t AwesomePlayer::pause() {
676 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700677
678 mFlags &= ~CACHE_UNDERRUN;
679
Andreas Huber27366fc2009-11-20 09:32:46 -0800680 return pause_l();
681}
682
683status_t AwesomePlayer::pause_l() {
684 if (!(mFlags & PLAYING)) {
685 return OK;
686 }
687
Andreas Huberb9e63832010-01-26 16:20:10 -0800688 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800689
690 if (mAudioPlayer != NULL) {
691 mAudioPlayer->pause();
692 }
693
694 mFlags &= ~PLAYING;
695
696 return OK;
697}
698
699bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700700 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800701}
702
703void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
704 Mutex::Autolock autoLock(mLock);
705
706 mISurface = isurface;
707}
708
709void AwesomePlayer::setAudioSink(
710 const sp<MediaPlayerBase::AudioSink> &audioSink) {
711 Mutex::Autolock autoLock(mLock);
712
713 mAudioSink = audioSink;
714}
715
716status_t AwesomePlayer::setLooping(bool shouldLoop) {
717 Mutex::Autolock autoLock(mLock);
718
719 mFlags = mFlags & ~LOOPING;
720
721 if (shouldLoop) {
722 mFlags |= LOOPING;
723 }
724
725 return OK;
726}
727
728status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700729 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800730
731 if (mDurationUs < 0) {
732 return UNKNOWN_ERROR;
733 }
734
735 *durationUs = mDurationUs;
736
737 return OK;
738}
739
740status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -0700741 if (mRTSPController != NULL) {
742 *positionUs = mRTSPController->getNormalPlayTimeUs();
743 }
744 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700745 *positionUs = mSeekTimeUs;
746 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700747 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800748 *positionUs = mVideoTimeUs;
749 } else if (mAudioPlayer != NULL) {
750 *positionUs = mAudioPlayer->getMediaTimeUs();
751 } else {
752 *positionUs = 0;
753 }
754
755 return OK;
756}
757
758status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700759 if (mExtractorFlags
760 & (MediaExtractor::CAN_SEEK_FORWARD
761 | MediaExtractor::CAN_SEEK_BACKWARD)) {
762 Mutex::Autolock autoLock(mLock);
763 return seekTo_l(timeUs);
764 }
765
766 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800767}
768
769status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700770 if (mRTSPController != NULL) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700771 mRTSPController->seek(timeUs);
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700772
773 notifyListener_l(MEDIA_SEEK_COMPLETE);
774 mSeekNotificationSent = true;
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700775 return OK;
776 }
777
Andreas Huber4d61f602010-06-10 11:17:50 -0700778 if (mFlags & CACHE_UNDERRUN) {
779 mFlags &= ~CACHE_UNDERRUN;
780 play_l();
781 }
782
Andreas Huber27366fc2009-11-20 09:32:46 -0800783 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700784 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800785 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700786 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -0800787
788 seekAudioIfNecessary_l();
789
Andreas Huber8e2b9412010-03-31 09:40:15 -0700790 if (!(mFlags & PLAYING)) {
791 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
792 " immediately.");
793
794 notifyListener_l(MEDIA_SEEK_COMPLETE);
795 mSeekNotificationSent = true;
796 }
797
Andreas Huber27366fc2009-11-20 09:32:46 -0800798 return OK;
799}
800
801void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800802 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800803 mAudioPlayer->seekTo(mSeekTimeUs);
804
Andreas Huber70d10c02010-02-03 11:37:29 -0800805 mWatchForAudioSeekComplete = true;
806 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700807 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800808 }
809}
810
811status_t AwesomePlayer::getVideoDimensions(
812 int32_t *width, int32_t *height) const {
813 Mutex::Autolock autoLock(mLock);
814
815 if (mVideoWidth < 0 || mVideoHeight < 0) {
816 return UNKNOWN_ERROR;
817 }
818
819 *width = mVideoWidth;
820 *height = mVideoHeight;
821
822 return OK;
823}
824
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800825void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
826 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800827
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800828 mAudioTrack = source;
829}
830
831status_t AwesomePlayer::initAudioDecoder() {
832 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800833
834 const char *mime;
835 CHECK(meta->findCString(kKeyMIMEType, &mime));
836
837 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800838 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800839 } else {
840 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800841 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800842 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800843 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800844 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800845
846 if (mAudioSource != NULL) {
847 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800848 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700849 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800850 if (mDurationUs < 0 || durationUs > mDurationUs) {
851 mDurationUs = durationUs;
852 }
853 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800854
Andreas Huber3c78a1b2010-05-13 09:15:21 -0700855 status_t err = mAudioSource->start();
856
857 if (err != OK) {
858 mAudioSource.clear();
859 return err;
860 }
Andreas Huberd0332ad2010-04-12 16:05:57 -0700861 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
862 // For legacy reasons we're simply going to ignore the absence
863 // of an audio decoder for QCELP instead of aborting playback
864 // altogether.
865 return OK;
866 }
Andreas Huberdc9927d2010-03-08 15:46:13 -0800867
Andreas Huber27366fc2009-11-20 09:32:46 -0800868 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
869}
870
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800871void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
872 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800873
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800874 mVideoTrack = source;
875}
876
877status_t AwesomePlayer::initVideoDecoder() {
Andreas Huber57648e42010-08-04 10:14:30 -0700878 uint32_t flags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800879 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800880 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -0800881 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -0700882 mVideoTrack,
883 NULL, flags);
Andreas Huber27366fc2009-11-20 09:32:46 -0800884
885 if (mVideoSource != NULL) {
886 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800887 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700888 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800889 if (mDurationUs < 0 || durationUs > mDurationUs) {
890 mDurationUs = durationUs;
891 }
892 }
893
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800894 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
895 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -0800896
Andreas Huber1919e5a2010-05-20 10:37:06 -0700897 status_t err = mVideoSource->start();
898
899 if (err != OK) {
900 mVideoSource.clear();
901 return err;
902 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800903 }
904
905 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
906}
907
Andreas Huber6be780e2010-02-08 14:40:30 -0800908void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800909 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800910 if (!mVideoEventPending) {
911 // The event has been cancelled in reset_l() but had already
912 // been scheduled for execution at that time.
913 return;
914 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800915 mVideoEventPending = false;
916
917 if (mSeeking) {
918 if (mLastVideoBuffer) {
919 mLastVideoBuffer->release();
920 mLastVideoBuffer = NULL;
921 }
922
923 if (mVideoBuffer) {
924 mVideoBuffer->release();
925 mVideoBuffer = NULL;
926 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700927
928 if (mCachedSource != NULL && mAudioSource != NULL) {
929 // We're going to seek the video source first, followed by
930 // the audio source.
931 // In order to avoid jumps in the DataSource offset caused by
932 // the audio codec prefetching data from the old locations
933 // while the video codec is already reading data from the new
934 // locations, we'll "pause" the audio source, causing it to
935 // stop reading input data until a subsequent seek.
936
937 if (mAudioPlayer != NULL) {
938 mAudioPlayer->pause();
939 }
940 mAudioSource->pause();
941 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800942 }
943
944 if (!mVideoBuffer) {
945 MediaSource::ReadOptions options;
946 if (mSeeking) {
947 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
948
Andreas Huber6624c9f2010-07-20 15:04:28 -0700949 options.setSeekTo(
950 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -0800951 }
952 for (;;) {
953 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800954 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800955
956 if (err != OK) {
957 CHECK_EQ(mVideoBuffer, NULL);
958
959 if (err == INFO_FORMAT_CHANGED) {
960 LOGV("VideoSource signalled format change.");
961
Andreas Huber7085b6842010-02-03 16:02:02 -0800962 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800963 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -0800964 initRenderer_l();
965 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800966 continue;
967 }
968
Andreas Huber971305d2010-07-07 13:35:27 -0700969 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -0800970 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -0800971 return;
972 }
973
Andreas Hubera67d5382009-12-10 15:32:12 -0800974 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800975 // Some decoders, notably the PV AVC software decoder
976 // return spurious empty buffers that we just want to ignore.
977
Andreas Hubera67d5382009-12-10 15:32:12 -0800978 mVideoBuffer->release();
979 mVideoBuffer = NULL;
980 continue;
981 }
982
Andreas Huber27366fc2009-11-20 09:32:46 -0800983 break;
984 }
985 }
986
987 int64_t timeUs;
988 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
989
Andreas Huber252573c2010-03-26 10:17:17 -0700990 {
991 Mutex::Autolock autoLock(mMiscStateLock);
992 mVideoTimeUs = timeUs;
993 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800994
995 if (mSeeking) {
996 if (mAudioPlayer != NULL) {
997 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
998
999 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -07001000 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -08001001 mWatchForAudioSeekComplete = true;
1002 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001003 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001004 // If we're playing video only, report seek complete now,
1005 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -08001006 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -08001007 }
1008
1009 mFlags |= FIRST_FRAME;
1010 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001011 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001012 }
1013
Andreas Huber971305d2010-07-07 13:35:27 -07001014 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1015
Andreas Huber27366fc2009-11-20 09:32:46 -08001016 if (mFlags & FIRST_FRAME) {
1017 mFlags &= ~FIRST_FRAME;
1018
Andreas Huber971305d2010-07-07 13:35:27 -07001019 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001020 }
1021
1022 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001023 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001024 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1025 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1026 }
1027
Andreas Huber971305d2010-07-07 13:35:27 -07001028 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001029
1030 int64_t latenessUs = nowUs - timeUs;
1031
Andreas Huberf88f8442010-08-10 11:18:36 -07001032 if (mRTPSession != NULL) {
1033 // We'll completely ignore timestamps for gtalk videochat
1034 // and we'll play incoming video as fast as we get it.
1035 latenessUs = 0;
1036 }
1037
Andreas Huber24b0a952009-11-23 14:02:00 -08001038 if (latenessUs > 40000) {
1039 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001040 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001041
1042 mVideoBuffer->release();
1043 mVideoBuffer = NULL;
1044
1045 postVideoEvent_l();
1046 return;
1047 }
1048
1049 if (latenessUs < -10000) {
1050 // We're more than 10ms early.
1051
1052 postVideoEvent_l(10000);
1053 return;
1054 }
1055
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001056 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1057 mVideoRendererIsPreview = false;
1058
Andreas Huber7085b6842010-02-03 16:02:02 -08001059 initRenderer_l();
1060 }
1061
1062 if (mVideoRenderer != NULL) {
1063 mVideoRenderer->render(mVideoBuffer);
1064 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001065
1066 if (mLastVideoBuffer) {
1067 mLastVideoBuffer->release();
1068 mLastVideoBuffer = NULL;
1069 }
1070 mLastVideoBuffer = mVideoBuffer;
1071 mVideoBuffer = NULL;
1072
1073 postVideoEvent_l();
1074}
1075
1076void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1077 if (mVideoEventPending) {
1078 return;
1079 }
1080
1081 mVideoEventPending = true;
1082 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1083}
1084
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001085void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001086 if (mStreamDoneEventPending) {
1087 return;
1088 }
1089 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001090
1091 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001092 mQueue.postEvent(mStreamDoneEvent);
1093}
1094
Andreas Huberb9e63832010-01-26 16:20:10 -08001095void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001096 if (mBufferingEventPending) {
1097 return;
1098 }
1099 mBufferingEventPending = true;
1100 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1101}
1102
Andreas Huber70d10c02010-02-03 11:37:29 -08001103void AwesomePlayer::postCheckAudioStatusEvent_l() {
1104 if (mAudioStatusEventPending) {
1105 return;
1106 }
1107 mAudioStatusEventPending = true;
1108 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
1109}
1110
1111void AwesomePlayer::onCheckAudioStatus() {
1112 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001113 if (!mAudioStatusEventPending) {
1114 // Event was dispatched and while we were blocking on the mutex,
1115 // has already been cancelled.
1116 return;
1117 }
1118
Andreas Huber70d10c02010-02-03 11:37:29 -08001119 mAudioStatusEventPending = false;
1120
1121 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1122 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001123
1124 if (!mSeekNotificationSent) {
1125 notifyListener_l(MEDIA_SEEK_COMPLETE);
1126 mSeekNotificationSent = true;
1127 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001128
1129 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001130 }
1131
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001132 status_t finalStatus;
1133 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001134 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001135 mFlags |= AUDIO_AT_EOS;
1136 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001137 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001138 }
1139
1140 postCheckAudioStatusEvent_l();
1141}
1142
Andreas Huber6be780e2010-02-08 14:40:30 -08001143status_t AwesomePlayer::prepare() {
1144 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001145 return prepare_l();
1146}
Andreas Huber6be780e2010-02-08 14:40:30 -08001147
Andreas Huberffdf4782010-02-09 14:05:43 -08001148status_t AwesomePlayer::prepare_l() {
1149 if (mFlags & PREPARED) {
1150 return OK;
1151 }
1152
1153 if (mFlags & PREPARING) {
1154 return UNKNOWN_ERROR;
1155 }
1156
1157 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001158 status_t err = prepareAsync_l();
1159
1160 if (err != OK) {
1161 return err;
1162 }
1163
Andreas Huberffdf4782010-02-09 14:05:43 -08001164 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001165 mPreparedCondition.wait(mLock);
1166 }
1167
Andreas Huberffdf4782010-02-09 14:05:43 -08001168 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001169}
1170
1171status_t AwesomePlayer::prepareAsync() {
1172 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001173
1174 if (mFlags & PREPARING) {
1175 return UNKNOWN_ERROR; // async prepare already pending
1176 }
1177
1178 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001179 return prepareAsync_l();
1180}
1181
1182status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001183 if (mFlags & PREPARING) {
1184 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001185 }
1186
Andreas Huber406a18b2010-02-18 16:45:13 -08001187 if (!mQueueStarted) {
1188 mQueue.start();
1189 mQueueStarted = true;
1190 }
1191
Andreas Huberffdf4782010-02-09 14:05:43 -08001192 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001193 mAsyncPrepareEvent = new AwesomeEvent(
1194 this, &AwesomePlayer::onPrepareAsyncEvent);
1195
1196 mQueue.postEvent(mAsyncPrepareEvent);
1197
1198 return OK;
1199}
1200
Andreas Huberffdf4782010-02-09 14:05:43 -08001201status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001202 sp<DataSource> dataSource;
1203
1204 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001205 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001206
1207 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001208 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001209 mLock.lock();
1210
1211 if (err != OK) {
1212 mConnectingDataSource.clear();
1213
1214 LOGI("mConnectingDataSource->connect() returned %d", err);
1215 return err;
1216 }
1217
Andreas Huber4d61f602010-06-10 11:17:50 -07001218#if 0
1219 mCachedSource = new NuCachedSource2(
1220 new ThrottledSource(
1221 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1222#else
1223 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1224#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001225 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001226
1227 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001228 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1229 String8 uri("http://");
1230 uri.append(mUri.string() + 11);
1231
1232 dataSource = new LiveSource(uri.string());
1233
Andreas Huber4d61f602010-06-10 11:17:50 -07001234 mCachedSource = new NuCachedSource2(dataSource);
1235 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001236
1237 sp<MediaExtractor> extractor =
1238 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001239
1240 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001241 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001242 if (mLooper == NULL) {
1243 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001244 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001245 mLooper->start(
1246 false /* runOnCallingThread */,
1247 false /* canCallJava */,
1248 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001249 }
1250
Mike Dodd8741dfa2010-08-12 16:04:35 -07001251 const char *startOfCodecString = &mUri.string()[13];
1252 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1253 if (startOfSlash1 == NULL) {
1254 return BAD_VALUE;
1255 }
1256 const char *startOfWidthString = &startOfSlash1[1];
1257 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1258 if (startOfSlash2 == NULL) {
1259 return BAD_VALUE;
1260 }
1261 const char *startOfHeightString = &startOfSlash2[1];
1262
1263 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1264 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1265 String8 heightString(startOfHeightString);
1266
Andreas Huber57648e42010-08-04 10:14:30 -07001267#if 0
1268 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1269 mLooper->registerHandler(mRTPPusher);
1270
1271 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1272 mLooper->registerHandler(mRTCPPusher);
1273#endif
1274
1275 mRTPSession = new ARTPSession;
1276 mLooper->registerHandler(mRTPSession);
1277
1278#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001279 // My AMR SDP
1280 static const char *raw =
1281 "v=0\r\n"
1282 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1283 "s=QuickTime\r\n"
1284 "t=0 0\r\n"
1285 "a=range:npt=0-315\r\n"
1286 "a=isma-compliance:2,2.0,2\r\n"
1287 "m=audio 5434 RTP/AVP 97\r\n"
1288 "c=IN IP4 127.0.0.1\r\n"
1289 "b=AS:30\r\n"
1290 "a=rtpmap:97 AMR/8000/1\r\n"
1291 "a=fmtp:97 octet-align\r\n";
1292#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001293 String8 sdp;
1294 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001295 "v=0\r\n"
1296 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1297 "s=QuickTime\r\n"
1298 "t=0 0\r\n"
1299 "a=range:npt=0-315\r\n"
1300 "a=isma-compliance:2,2.0,2\r\n"
1301 "m=video 5434 RTP/AVP 97\r\n"
1302 "c=IN IP4 127.0.0.1\r\n"
1303 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001304 "a=rtpmap:97 %s/90000\r\n"
1305 "a=cliprect:0,0,%s,%s\r\n"
1306 "a=framesize:97 %s-%s\r\n",
1307
1308 codecString.string(),
1309 heightString.string(), widthString.string(),
1310 widthString.string(), heightString.string()
1311 );
1312 const char *raw = sdp.string();
1313
Andreas Huber57648e42010-08-04 10:14:30 -07001314#endif
1315
1316 sp<ASessionDescription> desc = new ASessionDescription;
1317 CHECK(desc->setTo(raw, strlen(raw)));
1318
1319 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1320
1321 if (mRTPPusher != NULL) {
1322 mRTPPusher->start();
1323 }
1324
1325 if (mRTCPPusher != NULL) {
1326 mRTCPPusher->start();
1327 }
1328
1329 CHECK_EQ(mRTPSession->countTracks(), 1u);
1330 sp<MediaSource> source = mRTPSession->trackAt(0);
1331
1332#if 0
1333 bool eos;
1334 while (((APacketSource *)source.get())
1335 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1336 usleep(100000ll);
1337 }
1338#endif
1339
1340 const char *mime;
1341 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1342
1343 if (!strncasecmp("video/", mime, 6)) {
1344 setVideoSource(source);
1345 } else {
1346 CHECK(!strncasecmp("audio/", mime, 6));
1347 setAudioSource(source);
1348 }
1349
1350 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1351
1352 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001353 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1354 if (mLooper == NULL) {
1355 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001356 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001357 mLooper->start();
1358 }
1359 mRTSPController = new ARTSPController(mLooper);
1360 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001361
Andreas Huber7a747b82010-06-07 15:19:40 -07001362 LOGI("ARTSPController::connect returned %d", err);
1363
1364 if (err != OK) {
1365 mRTSPController.clear();
1366 return err;
1367 }
1368
1369 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001370 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001371 } else {
1372 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1373 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001374
1375 if (dataSource == NULL) {
1376 return UNKNOWN_ERROR;
1377 }
1378
1379 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1380
1381 if (extractor == NULL) {
1382 return UNKNOWN_ERROR;
1383 }
1384
Andreas Huberffdf4782010-02-09 14:05:43 -08001385 return setDataSource_l(extractor);
1386}
1387
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001388void AwesomePlayer::abortPrepare(status_t err) {
1389 CHECK(err != OK);
1390
1391 if (mIsAsyncPrepare) {
1392 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1393 }
1394
1395 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001396 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001397 mAsyncPrepareEvent = NULL;
1398 mPreparedCondition.broadcast();
1399}
1400
Andreas Huberf71daba2010-03-24 09:24:40 -07001401// static
1402bool AwesomePlayer::ContinuePreparation(void *cookie) {
1403 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1404
1405 return (me->mFlags & PREPARE_CANCELLED) == 0;
1406}
1407
Andreas Huber6be780e2010-02-08 14:40:30 -08001408void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001409 {
1410 Mutex::Autolock autoLock(mLock);
1411
Andreas Huberedbb4d82010-03-12 08:59:22 -08001412 if (mFlags & PREPARE_CANCELLED) {
1413 LOGI("prepare was cancelled before doing anything");
1414 abortPrepare(UNKNOWN_ERROR);
1415 return;
1416 }
1417
Andreas Huberffdf4782010-02-09 14:05:43 -08001418 if (mUri.size() > 0) {
1419 status_t err = finishSetDataSource_l();
1420
1421 if (err != OK) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001422 abortPrepare(err);
Andreas Huberffdf4782010-02-09 14:05:43 -08001423 return;
1424 }
1425 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001426
Andreas Huber55864df72010-03-08 12:28:22 -08001427 if (mVideoTrack != NULL && mVideoSource == NULL) {
1428 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001429
Andreas Huber55864df72010-03-08 12:28:22 -08001430 if (err != OK) {
1431 abortPrepare(err);
1432 return;
1433 }
1434 }
1435
1436 if (mAudioTrack != NULL && mAudioSource == NULL) {
1437 status_t err = initAudioDecoder();
1438
1439 if (err != OK) {
1440 abortPrepare(err);
1441 return;
1442 }
1443 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001444 }
1445
1446 Mutex::Autolock autoLock(mLock);
1447
Andreas Huberffdf4782010-02-09 14:05:43 -08001448 if (mIsAsyncPrepare) {
1449 if (mVideoWidth < 0 || mVideoHeight < 0) {
1450 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1451 } else {
1452 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1453 }
1454
1455 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001456 }
1457
Andreas Huberffdf4782010-02-09 14:05:43 -08001458 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001459 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001460 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001461 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001462 mPreparedCondition.broadcast();
Andreas Huber040301c2010-04-12 09:41:12 -07001463
1464 postBufferingEvent_l();
Andreas Huber6be780e2010-02-08 14:40:30 -08001465}
1466
Andreas Huberba7ec912010-02-12 10:42:02 -08001467status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001468 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001469 Mutex::Autolock autoLock(mLock);
1470
1471 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001472 if (mLastVideoBuffer == NULL) {
1473 //go into here if video is suspended again
1474 //after resuming without being played between
1475 //them
1476 SuspensionState *state = mSuspensionState;
1477 mSuspensionState = NULL;
1478 reset_l();
1479 mSuspensionState = state;
1480 return OK;
1481 }
1482
1483 delete mSuspensionState;
1484 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001485 }
1486
Andreas Huberedbb4d82010-03-12 08:59:22 -08001487 if (mFlags & PREPARING) {
1488 mFlags |= PREPARE_CANCELLED;
1489 if (mConnectingDataSource != NULL) {
1490 LOGI("interrupting the connection process");
1491 mConnectingDataSource->disconnect();
1492 }
1493 }
1494
Andreas Huberba7ec912010-02-12 10:42:02 -08001495 while (mFlags & PREPARING) {
1496 mPreparedCondition.wait(mLock);
1497 }
1498
1499 SuspensionState *state = new SuspensionState;
1500 state->mUri = mUri;
1501 state->mUriHeaders = mUriHeaders;
1502 state->mFileSource = mFileSource;
1503
Andreas Huber406a18b2010-02-18 16:45:13 -08001504 state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001505 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001506
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001507 if (mLastVideoBuffer) {
1508 size_t size = mLastVideoBuffer->range_length();
1509 if (size) {
1510 state->mLastVideoFrameSize = size;
1511 state->mLastVideoFrame = malloc(size);
1512 memcpy(state->mLastVideoFrame,
1513 (const uint8_t *)mLastVideoBuffer->data()
1514 + mLastVideoBuffer->range_offset(),
1515 size);
1516
1517 state->mVideoWidth = mVideoWidth;
1518 state->mVideoHeight = mVideoHeight;
1519
1520 sp<MetaData> meta = mVideoSource->getFormat();
1521 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1522 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1523 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1524 }
1525 }
1526
Andreas Huberba7ec912010-02-12 10:42:02 -08001527 reset_l();
1528
1529 mSuspensionState = state;
1530
1531 return OK;
1532}
1533
1534status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001535 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001536 Mutex::Autolock autoLock(mLock);
1537
1538 if (mSuspensionState == NULL) {
1539 return INVALID_OPERATION;
1540 }
1541
1542 SuspensionState *state = mSuspensionState;
1543 mSuspensionState = NULL;
1544
1545 status_t err;
1546 if (state->mFileSource != NULL) {
1547 err = setDataSource_l(state->mFileSource);
1548
1549 if (err == OK) {
1550 mFileSource = state->mFileSource;
1551 }
1552 } else {
1553 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1554 }
1555
1556 if (err != OK) {
1557 delete state;
1558 state = NULL;
1559
1560 return err;
1561 }
1562
1563 seekTo_l(state->mPositionUs);
1564
Andreas Huber406a18b2010-02-18 16:45:13 -08001565 mFlags = state->mFlags & (LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001566
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001567 if (state->mLastVideoFrame && mISurface != NULL) {
1568 mVideoRenderer =
1569 new AwesomeLocalRenderer(
1570 true, // previewOnly
1571 "",
1572 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1573 mISurface,
1574 state->mVideoWidth,
1575 state->mVideoHeight,
1576 state->mDecodedWidth,
1577 state->mDecodedHeight);
1578
1579 mVideoRendererIsPreview = true;
1580
1581 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1582 state->mLastVideoFrame, state->mLastVideoFrameSize);
1583 }
1584
Andreas Huberba7ec912010-02-12 10:42:02 -08001585 if (state->mFlags & PLAYING) {
1586 play_l();
1587 }
1588
Gloria Wangb19da8e2010-04-12 17:13:06 -07001589 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001590 state = NULL;
1591
1592 return OK;
1593}
1594
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001595uint32_t AwesomePlayer::flags() const {
1596 return mExtractorFlags;
1597}
1598
Andreas Huber27366fc2009-11-20 09:32:46 -08001599} // namespace android
1600