blob: e426fca16314320fbb21d83c4aed2959fa28827c [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 Huber7a747b82010-06-07 15:19:40 -0700396 mRTSPController.clear();
Andreas Huber57648e42010-08-04 10:14:30 -0700397 mRTPPusher.clear();
398 mRTCPPusher.clear();
399 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700400
Andreas Huber27366fc2009-11-20 09:32:46 -0800401 if (mVideoSource != NULL) {
402 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800403
404 // The following hack is necessary to ensure that the OMX
405 // component is completely released by the time we may try
406 // to instantiate it again.
407 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800408 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800409 while (tmp.promote() != NULL) {
410 usleep(1000);
411 }
412 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800413 }
414
Andreas Huber27366fc2009-11-20 09:32:46 -0800415 mDurationUs = -1;
416 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700417 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800418 mVideoWidth = mVideoHeight = -1;
419 mTimeSourceDeltaUs = 0;
420 mVideoTimeUs = 0;
421
422 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700423 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800424 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800425
Andreas Huberffdf4782010-02-09 14:05:43 -0800426 mUri.setTo("");
427 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800428
429 mFileSource.clear();
430
431 delete mSuspensionState;
432 mSuspensionState = NULL;
Andreas Huber27366fc2009-11-20 09:32:46 -0800433}
434
Andreas Huber6be780e2010-02-08 14:40:30 -0800435void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800436 if (mListener != NULL) {
437 sp<MediaPlayerBase> listener = mListener.promote();
438
439 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800440 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800441 }
442 }
443}
444
Andreas Huberb9e63832010-01-26 16:20:10 -0800445void AwesomePlayer::onBufferingUpdate() {
446 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800447 if (!mBufferingEventPending) {
448 return;
449 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800450 mBufferingEventPending = false;
451
Andreas Huber4d61f602010-06-10 11:17:50 -0700452 if (mCachedSource == NULL) {
453 return;
Andreas Huber252573c2010-03-26 10:17:17 -0700454 }
455
Andreas Huber4d61f602010-06-10 11:17:50 -0700456 size_t lowWatermark = 400000;
457 size_t highWatermark = 1000000;
Andreas Huber202348e2010-06-07 14:35:29 -0700458
Andreas Huber4d61f602010-06-10 11:17:50 -0700459 off_t size;
460 if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
461 int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
Andreas Huber202348e2010-06-07 14:35:29 -0700462
Andreas Huber4d61f602010-06-10 11:17:50 -0700463 size_t cachedSize = mCachedSource->cachedSize();
464 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
Andreas Huberb9e63832010-01-26 16:20:10 -0800465
Andreas Huber4d61f602010-06-10 11:17:50 -0700466 double percentage = (double)cachedDurationUs / mDurationUs;
Andreas Huberb9e63832010-01-26 16:20:10 -0800467
Andreas Huberb9e63832010-01-26 16:20:10 -0800468 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
469
Andreas Huber4d61f602010-06-10 11:17:50 -0700470 lowWatermark = 2 * bitrate / 8; // 2 secs
471 highWatermark = 10 * bitrate / 8; // 10 secs
Andreas Huberb9e63832010-01-26 16:20:10 -0800472 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700473
474 bool eos;
475 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
476
477 if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
478 LOGI("cache is running low (< %d) , pausing.", lowWatermark);
479 mFlags |= CACHE_UNDERRUN;
480 pause_l();
481 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
482 } else if ((mFlags & CACHE_UNDERRUN)
483 && (eos || cachedDataRemaining > highWatermark)) {
484 LOGI("cache has filled up (> %d), resuming.", highWatermark);
485 mFlags &= ~CACHE_UNDERRUN;
486 play_l();
487 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
488 }
489
490 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800491}
492
Andreas Huber27366fc2009-11-20 09:32:46 -0800493void AwesomePlayer::onStreamDone() {
494 // Posted whenever any stream finishes playing.
495
496 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800497 if (!mStreamDoneEventPending) {
498 return;
499 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800500 mStreamDoneEventPending = false;
501
Andreas Huber971305d2010-07-07 13:35:27 -0700502 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
503 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
504
505 notifyListener_l(
506 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
507
508 pause_l();
509
510 mFlags |= AT_EOS;
511 return;
512 }
513
514 const bool allDone =
515 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
516 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
517
518 if (!allDone) {
519 return;
520 }
521
522 if (mFlags & LOOPING) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800523 seekTo_l(0);
524
Andreas Huber7085b6842010-02-03 16:02:02 -0800525 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800526 postVideoEvent_l();
527 }
528 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700529 LOGV("MEDIA_PLAYBACK_COMPLETE");
530 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800531
532 pause_l();
Andreas Huber406a18b2010-02-18 16:45:13 -0800533
534 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800535 }
536}
537
538status_t AwesomePlayer::play() {
539 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700540
541 mFlags &= ~CACHE_UNDERRUN;
542
Andreas Huberba7ec912010-02-12 10:42:02 -0800543 return play_l();
544}
Andreas Huber27366fc2009-11-20 09:32:46 -0800545
Andreas Huberba7ec912010-02-12 10:42:02 -0800546status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800547 if (mFlags & PLAYING) {
548 return OK;
549 }
550
Andreas Huberffdf4782010-02-09 14:05:43 -0800551 if (!(mFlags & PREPARED)) {
552 status_t err = prepare_l();
553
554 if (err != OK) {
555 return err;
556 }
557 }
558
Andreas Huber27366fc2009-11-20 09:32:46 -0800559 mFlags |= PLAYING;
560 mFlags |= FIRST_FRAME;
561
Andreas Huberc1d5c922009-12-10 15:49:04 -0800562 bool deferredAudioSeek = false;
563
Andreas Huber27366fc2009-11-20 09:32:46 -0800564 if (mAudioSource != NULL) {
565 if (mAudioPlayer == NULL) {
566 if (mAudioSink != NULL) {
567 mAudioPlayer = new AudioPlayer(mAudioSink);
Andreas Huber27366fc2009-11-20 09:32:46 -0800568 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800569
570 // We've already started the MediaSource in order to enable
571 // the prefetcher to read its data.
572 status_t err = mAudioPlayer->start(
573 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800574
575 if (err != OK) {
576 delete mAudioPlayer;
577 mAudioPlayer = NULL;
578
579 mFlags &= ~(PLAYING | FIRST_FRAME);
580
581 return err;
582 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800583
Andreas Huber27366fc2009-11-20 09:32:46 -0800584 mTimeSource = mAudioPlayer;
585
Andreas Huberc1d5c922009-12-10 15:49:04 -0800586 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800587
588 mWatchForAudioSeekComplete = false;
589 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800590 }
591 } else {
592 mAudioPlayer->resume();
593 }
Andreas Huber70d10c02010-02-03 11:37:29 -0800594
595 postCheckAudioStatusEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800596 }
597
598 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700599 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800600 }
601
602 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800603 // Kick off video playback
604 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800605 }
606
Andreas Huberc1d5c922009-12-10 15:49:04 -0800607 if (deferredAudioSeek) {
608 // If there was a seek request while we were paused
609 // and we're just starting up again, honor the request now.
610 seekAudioIfNecessary_l();
611 }
612
Andreas Huber406a18b2010-02-18 16:45:13 -0800613 if (mFlags & AT_EOS) {
614 // Legacy behaviour, if a stream finishes playing and then
615 // is started again, we play from the start...
616 seekTo_l(0);
617 }
618
Andreas Huber27366fc2009-11-20 09:32:46 -0800619 return OK;
620}
621
622void AwesomePlayer::initRenderer_l() {
623 if (mISurface != NULL) {
624 sp<MetaData> meta = mVideoSource->getFormat();
625
626 int32_t format;
627 const char *component;
628 int32_t decodedWidth, decodedHeight;
629 CHECK(meta->findInt32(kKeyColorFormat, &format));
630 CHECK(meta->findCString(kKeyDecoderComponent, &component));
631 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
632 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
633
Andreas Hubera67d5382009-12-10 15:32:12 -0800634 mVideoRenderer.clear();
635
636 // Must ensure that mVideoRenderer's destructor is actually executed
637 // before creating a new one.
638 IPCThreadState::self()->flushCommands();
639
Andreas Huber1314e732009-12-14 14:18:22 -0800640 if (!strncmp("OMX.", component, 4)) {
641 // Our OMX codecs allocate buffers on the media_server side
642 // therefore they require a remote IOMXRenderer that knows how
643 // to display them.
644 mVideoRenderer = new AwesomeRemoteRenderer(
645 mClient.interface()->createRenderer(
646 mISurface, component,
647 (OMX_COLOR_FORMATTYPE)format,
648 decodedWidth, decodedHeight,
649 mVideoWidth, mVideoHeight));
650 } else {
651 // Other decoders are instantiated locally and as a consequence
652 // allocate their buffers in local address space.
653 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800654 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800655 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800656 (OMX_COLOR_FORMATTYPE)format,
657 mISurface,
658 mVideoWidth, mVideoHeight,
659 decodedWidth, decodedHeight);
660 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800661 }
662}
663
664status_t AwesomePlayer::pause() {
665 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700666
667 mFlags &= ~CACHE_UNDERRUN;
668
Andreas Huber27366fc2009-11-20 09:32:46 -0800669 return pause_l();
670}
671
672status_t AwesomePlayer::pause_l() {
673 if (!(mFlags & PLAYING)) {
674 return OK;
675 }
676
Andreas Huberb9e63832010-01-26 16:20:10 -0800677 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800678
679 if (mAudioPlayer != NULL) {
680 mAudioPlayer->pause();
681 }
682
683 mFlags &= ~PLAYING;
684
685 return OK;
686}
687
688bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700689 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800690}
691
692void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
693 Mutex::Autolock autoLock(mLock);
694
695 mISurface = isurface;
696}
697
698void AwesomePlayer::setAudioSink(
699 const sp<MediaPlayerBase::AudioSink> &audioSink) {
700 Mutex::Autolock autoLock(mLock);
701
702 mAudioSink = audioSink;
703}
704
705status_t AwesomePlayer::setLooping(bool shouldLoop) {
706 Mutex::Autolock autoLock(mLock);
707
708 mFlags = mFlags & ~LOOPING;
709
710 if (shouldLoop) {
711 mFlags |= LOOPING;
712 }
713
714 return OK;
715}
716
717status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700718 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800719
720 if (mDurationUs < 0) {
721 return UNKNOWN_ERROR;
722 }
723
724 *durationUs = mDurationUs;
725
726 return OK;
727}
728
729status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700730 if (mSeeking) {
731 *positionUs = mSeekTimeUs;
732 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700733 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800734 *positionUs = mVideoTimeUs;
735 } else if (mAudioPlayer != NULL) {
736 *positionUs = mAudioPlayer->getMediaTimeUs();
737 } else {
738 *positionUs = 0;
739 }
740
741 return OK;
742}
743
744status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700745 if (mExtractorFlags
746 & (MediaExtractor::CAN_SEEK_FORWARD
747 | MediaExtractor::CAN_SEEK_BACKWARD)) {
748 Mutex::Autolock autoLock(mLock);
749 return seekTo_l(timeUs);
750 }
751
752 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800753}
754
755status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Huber4d61f602010-06-10 11:17:50 -0700756 if (mFlags & CACHE_UNDERRUN) {
757 mFlags &= ~CACHE_UNDERRUN;
758 play_l();
759 }
760
Andreas Huber27366fc2009-11-20 09:32:46 -0800761 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700762 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800763 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700764 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -0800765
766 seekAudioIfNecessary_l();
767
Andreas Huber8e2b9412010-03-31 09:40:15 -0700768 if (!(mFlags & PLAYING)) {
769 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
770 " immediately.");
771
772 notifyListener_l(MEDIA_SEEK_COMPLETE);
773 mSeekNotificationSent = true;
774 }
775
Andreas Huber27366fc2009-11-20 09:32:46 -0800776 return OK;
777}
778
779void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800780 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800781 mAudioPlayer->seekTo(mSeekTimeUs);
782
Andreas Huber70d10c02010-02-03 11:37:29 -0800783 mWatchForAudioSeekComplete = true;
784 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700785 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800786 }
787}
788
789status_t AwesomePlayer::getVideoDimensions(
790 int32_t *width, int32_t *height) const {
791 Mutex::Autolock autoLock(mLock);
792
793 if (mVideoWidth < 0 || mVideoHeight < 0) {
794 return UNKNOWN_ERROR;
795 }
796
797 *width = mVideoWidth;
798 *height = mVideoHeight;
799
800 return OK;
801}
802
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800803void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
804 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800805
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800806 mAudioTrack = source;
807}
808
809status_t AwesomePlayer::initAudioDecoder() {
810 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800811
812 const char *mime;
813 CHECK(meta->findCString(kKeyMIMEType, &mime));
814
815 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800816 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800817 } else {
818 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800819 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800820 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800821 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800822 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800823
824 if (mAudioSource != NULL) {
825 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800826 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700827 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800828 if (mDurationUs < 0 || durationUs > mDurationUs) {
829 mDurationUs = durationUs;
830 }
831 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800832
Andreas Huber3c78a1b2010-05-13 09:15:21 -0700833 status_t err = mAudioSource->start();
834
835 if (err != OK) {
836 mAudioSource.clear();
837 return err;
838 }
Andreas Huberd0332ad2010-04-12 16:05:57 -0700839 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
840 // For legacy reasons we're simply going to ignore the absence
841 // of an audio decoder for QCELP instead of aborting playback
842 // altogether.
843 return OK;
844 }
Andreas Huberdc9927d2010-03-08 15:46:13 -0800845
Andreas Huber27366fc2009-11-20 09:32:46 -0800846 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
847}
848
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800849void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
850 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800851
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800852 mVideoTrack = source;
853}
854
855status_t AwesomePlayer::initVideoDecoder() {
Andreas Huber57648e42010-08-04 10:14:30 -0700856 uint32_t flags = 0;
Andreas Huber426b6502010-08-04 14:04:31 -0700857#if 0
Andreas Huber57648e42010-08-04 10:14:30 -0700858 if (mRTPSession != NULL) {
859 // XXX hack.
860
861 const char *mime;
862 CHECK(mVideoTrack->getFormat()->findCString(kKeyMIMEType, &mime));
863 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
864 flags |= OMXCodec::kPreferSoftwareCodecs;
865 }
866 }
867#endif
868
Andreas Huber27366fc2009-11-20 09:32:46 -0800869 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800870 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -0800871 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -0700872 mVideoTrack,
873 NULL, flags);
Andreas Huber27366fc2009-11-20 09:32:46 -0800874
875 if (mVideoSource != NULL) {
876 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800877 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700878 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800879 if (mDurationUs < 0 || durationUs > mDurationUs) {
880 mDurationUs = durationUs;
881 }
882 }
883
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800884 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
885 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -0800886
Andreas Huber1919e5a2010-05-20 10:37:06 -0700887 status_t err = mVideoSource->start();
888
889 if (err != OK) {
890 mVideoSource.clear();
891 return err;
892 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800893 }
894
895 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
896}
897
Andreas Huber6be780e2010-02-08 14:40:30 -0800898void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800899 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800900 if (!mVideoEventPending) {
901 // The event has been cancelled in reset_l() but had already
902 // been scheduled for execution at that time.
903 return;
904 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800905 mVideoEventPending = false;
906
907 if (mSeeking) {
908 if (mLastVideoBuffer) {
909 mLastVideoBuffer->release();
910 mLastVideoBuffer = NULL;
911 }
912
913 if (mVideoBuffer) {
914 mVideoBuffer->release();
915 mVideoBuffer = NULL;
916 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700917
918 if (mCachedSource != NULL && mAudioSource != NULL) {
919 // We're going to seek the video source first, followed by
920 // the audio source.
921 // In order to avoid jumps in the DataSource offset caused by
922 // the audio codec prefetching data from the old locations
923 // while the video codec is already reading data from the new
924 // locations, we'll "pause" the audio source, causing it to
925 // stop reading input data until a subsequent seek.
926
927 if (mAudioPlayer != NULL) {
928 mAudioPlayer->pause();
929 }
930 mAudioSource->pause();
931 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800932 }
933
934 if (!mVideoBuffer) {
935 MediaSource::ReadOptions options;
936 if (mSeeking) {
937 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
938
Andreas Huber6624c9f2010-07-20 15:04:28 -0700939 options.setSeekTo(
940 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -0800941 }
942 for (;;) {
943 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -0800944 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -0800945
946 if (err != OK) {
947 CHECK_EQ(mVideoBuffer, NULL);
948
949 if (err == INFO_FORMAT_CHANGED) {
950 LOGV("VideoSource signalled format change.");
951
Andreas Huber7085b6842010-02-03 16:02:02 -0800952 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800953 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -0800954 initRenderer_l();
955 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800956 continue;
957 }
958
Andreas Huber971305d2010-07-07 13:35:27 -0700959 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -0800960 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -0800961 return;
962 }
963
Andreas Hubera67d5382009-12-10 15:32:12 -0800964 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -0800965 // Some decoders, notably the PV AVC software decoder
966 // return spurious empty buffers that we just want to ignore.
967
Andreas Hubera67d5382009-12-10 15:32:12 -0800968 mVideoBuffer->release();
969 mVideoBuffer = NULL;
970 continue;
971 }
972
Andreas Huber27366fc2009-11-20 09:32:46 -0800973 break;
974 }
975 }
976
977 int64_t timeUs;
978 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
979
Andreas Huber252573c2010-03-26 10:17:17 -0700980 {
981 Mutex::Autolock autoLock(mMiscStateLock);
982 mVideoTimeUs = timeUs;
983 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800984
985 if (mSeeking) {
986 if (mAudioPlayer != NULL) {
987 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
988
989 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -0700990 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -0800991 mWatchForAudioSeekComplete = true;
992 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700993 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800994 // If we're playing video only, report seek complete now,
995 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -0800996 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800997 }
998
999 mFlags |= FIRST_FRAME;
1000 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001001 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001002 }
1003
Andreas Huber971305d2010-07-07 13:35:27 -07001004 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1005
Andreas Huber27366fc2009-11-20 09:32:46 -08001006 if (mFlags & FIRST_FRAME) {
1007 mFlags &= ~FIRST_FRAME;
1008
Andreas Huber971305d2010-07-07 13:35:27 -07001009 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001010 }
1011
1012 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001013 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001014 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1015 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1016 }
1017
Andreas Huber971305d2010-07-07 13:35:27 -07001018 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001019
1020 int64_t latenessUs = nowUs - timeUs;
1021
Andreas Huber24b0a952009-11-23 14:02:00 -08001022 if (latenessUs > 40000) {
1023 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001024 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001025
1026 mVideoBuffer->release();
1027 mVideoBuffer = NULL;
1028
1029 postVideoEvent_l();
1030 return;
1031 }
1032
1033 if (latenessUs < -10000) {
1034 // We're more than 10ms early.
1035
1036 postVideoEvent_l(10000);
1037 return;
1038 }
1039
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001040 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1041 mVideoRendererIsPreview = false;
1042
Andreas Huber7085b6842010-02-03 16:02:02 -08001043 initRenderer_l();
1044 }
1045
1046 if (mVideoRenderer != NULL) {
1047 mVideoRenderer->render(mVideoBuffer);
1048 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001049
1050 if (mLastVideoBuffer) {
1051 mLastVideoBuffer->release();
1052 mLastVideoBuffer = NULL;
1053 }
1054 mLastVideoBuffer = mVideoBuffer;
1055 mVideoBuffer = NULL;
1056
1057 postVideoEvent_l();
1058}
1059
1060void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1061 if (mVideoEventPending) {
1062 return;
1063 }
1064
1065 mVideoEventPending = true;
1066 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1067}
1068
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001069void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001070 if (mStreamDoneEventPending) {
1071 return;
1072 }
1073 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001074
1075 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001076 mQueue.postEvent(mStreamDoneEvent);
1077}
1078
Andreas Huberb9e63832010-01-26 16:20:10 -08001079void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001080 if (mBufferingEventPending) {
1081 return;
1082 }
1083 mBufferingEventPending = true;
1084 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1085}
1086
Andreas Huber70d10c02010-02-03 11:37:29 -08001087void AwesomePlayer::postCheckAudioStatusEvent_l() {
1088 if (mAudioStatusEventPending) {
1089 return;
1090 }
1091 mAudioStatusEventPending = true;
1092 mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
1093}
1094
1095void AwesomePlayer::onCheckAudioStatus() {
1096 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001097 if (!mAudioStatusEventPending) {
1098 // Event was dispatched and while we were blocking on the mutex,
1099 // has already been cancelled.
1100 return;
1101 }
1102
Andreas Huber70d10c02010-02-03 11:37:29 -08001103 mAudioStatusEventPending = false;
1104
1105 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1106 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001107
1108 if (!mSeekNotificationSent) {
1109 notifyListener_l(MEDIA_SEEK_COMPLETE);
1110 mSeekNotificationSent = true;
1111 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001112
1113 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001114 }
1115
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001116 status_t finalStatus;
1117 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001118 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001119 mFlags |= AUDIO_AT_EOS;
1120 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001121 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001122 }
1123
1124 postCheckAudioStatusEvent_l();
1125}
1126
Andreas Huber6be780e2010-02-08 14:40:30 -08001127status_t AwesomePlayer::prepare() {
1128 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001129 return prepare_l();
1130}
Andreas Huber6be780e2010-02-08 14:40:30 -08001131
Andreas Huberffdf4782010-02-09 14:05:43 -08001132status_t AwesomePlayer::prepare_l() {
1133 if (mFlags & PREPARED) {
1134 return OK;
1135 }
1136
1137 if (mFlags & PREPARING) {
1138 return UNKNOWN_ERROR;
1139 }
1140
1141 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001142 status_t err = prepareAsync_l();
1143
1144 if (err != OK) {
1145 return err;
1146 }
1147
Andreas Huberffdf4782010-02-09 14:05:43 -08001148 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001149 mPreparedCondition.wait(mLock);
1150 }
1151
Andreas Huberffdf4782010-02-09 14:05:43 -08001152 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001153}
1154
1155status_t AwesomePlayer::prepareAsync() {
1156 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001157
1158 if (mFlags & PREPARING) {
1159 return UNKNOWN_ERROR; // async prepare already pending
1160 }
1161
1162 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001163 return prepareAsync_l();
1164}
1165
1166status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001167 if (mFlags & PREPARING) {
1168 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001169 }
1170
Andreas Huber406a18b2010-02-18 16:45:13 -08001171 if (!mQueueStarted) {
1172 mQueue.start();
1173 mQueueStarted = true;
1174 }
1175
Andreas Huberffdf4782010-02-09 14:05:43 -08001176 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001177 mAsyncPrepareEvent = new AwesomeEvent(
1178 this, &AwesomePlayer::onPrepareAsyncEvent);
1179
1180 mQueue.postEvent(mAsyncPrepareEvent);
1181
1182 return OK;
1183}
1184
Andreas Huberffdf4782010-02-09 14:05:43 -08001185status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001186 sp<DataSource> dataSource;
1187
1188 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001189 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001190
1191 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001192 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001193 mLock.lock();
1194
1195 if (err != OK) {
1196 mConnectingDataSource.clear();
1197
1198 LOGI("mConnectingDataSource->connect() returned %d", err);
1199 return err;
1200 }
1201
Andreas Huber4d61f602010-06-10 11:17:50 -07001202#if 0
1203 mCachedSource = new NuCachedSource2(
1204 new ThrottledSource(
1205 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1206#else
1207 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1208#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001209 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001210
1211 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001212 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1213 String8 uri("http://");
1214 uri.append(mUri.string() + 11);
1215
1216 dataSource = new LiveSource(uri.string());
1217
Andreas Huber4d61f602010-06-10 11:17:50 -07001218 mCachedSource = new NuCachedSource2(dataSource);
1219 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001220
1221 sp<MediaExtractor> extractor =
1222 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001223
1224 return setDataSource_l(extractor);
Andreas Huber57648e42010-08-04 10:14:30 -07001225 } else if (!strcmp("rtsp://gtalk", mUri.string())) {
1226 if (mLooper == NULL) {
1227 mLooper = new ALooper;
Andreas Huber3eaa3002010-08-05 09:22:25 -07001228 mLooper->start(
1229 false /* runOnCallingThread */,
1230 false /* canCallJava */,
1231 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001232 }
1233
1234#if 0
1235 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1236 mLooper->registerHandler(mRTPPusher);
1237
1238 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1239 mLooper->registerHandler(mRTCPPusher);
1240#endif
1241
1242 mRTPSession = new ARTPSession;
1243 mLooper->registerHandler(mRTPSession);
1244
1245#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001246 // My AMR SDP
1247 static const char *raw =
1248 "v=0\r\n"
1249 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1250 "s=QuickTime\r\n"
1251 "t=0 0\r\n"
1252 "a=range:npt=0-315\r\n"
1253 "a=isma-compliance:2,2.0,2\r\n"
1254 "m=audio 5434 RTP/AVP 97\r\n"
1255 "c=IN IP4 127.0.0.1\r\n"
1256 "b=AS:30\r\n"
1257 "a=rtpmap:97 AMR/8000/1\r\n"
1258 "a=fmtp:97 octet-align\r\n";
1259#elif 1
1260 // My GTalk H.264 SDP
1261 static const char *raw =
1262 "v=0\r\n"
1263 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1264 "s=QuickTime\r\n"
1265 "t=0 0\r\n"
1266 "a=range:npt=0-315\r\n"
1267 "a=isma-compliance:2,2.0,2\r\n"
1268 "m=video 5434 RTP/AVP 97\r\n"
1269 "c=IN IP4 127.0.0.1\r\n"
1270 "b=AS:30\r\n"
1271 "a=rtpmap:97 H264/90000\r\n"
Andreas Huber57648e42010-08-04 10:14:30 -07001272 "a=cliprect:0,0,200,320\r\n"
1273 "a=framesize:97 320-200\r\n";
Andreas Huber426b6502010-08-04 14:04:31 -07001274#else
Andreas Huber57648e42010-08-04 10:14:30 -07001275 // GTalk H263 SDP
1276 static const char *raw =
1277 "v=0\r\n"
1278 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1279 "s=QuickTime\r\n"
1280 "t=0 0\r\n"
1281 "a=range:npt=0-315\r\n"
1282 "a=isma-compliance:2,2.0,2\r\n"
1283 "m=video 5434 RTP/AVP 98\r\n"
1284 "c=IN IP4 127.0.0.1\r\n"
1285 "b=AS:30\r\n"
1286 "a=rtpmap:98 H263-1998/90000\r\n"
1287 "a=cliprect:0,0,200,320\r\n"
1288 "a=framesize:98 320-200\r\n";
Andreas Huber57648e42010-08-04 10:14:30 -07001289#endif
1290
1291 sp<ASessionDescription> desc = new ASessionDescription;
1292 CHECK(desc->setTo(raw, strlen(raw)));
1293
1294 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1295
1296 if (mRTPPusher != NULL) {
1297 mRTPPusher->start();
1298 }
1299
1300 if (mRTCPPusher != NULL) {
1301 mRTCPPusher->start();
1302 }
1303
1304 CHECK_EQ(mRTPSession->countTracks(), 1u);
1305 sp<MediaSource> source = mRTPSession->trackAt(0);
1306
1307#if 0
1308 bool eos;
1309 while (((APacketSource *)source.get())
1310 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1311 usleep(100000ll);
1312 }
1313#endif
1314
1315 const char *mime;
1316 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1317
1318 if (!strncasecmp("video/", mime, 6)) {
1319 setVideoSource(source);
1320 } else {
1321 CHECK(!strncasecmp("audio/", mime, 6));
1322 setAudioSource(source);
1323 }
1324
1325 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1326
1327 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001328 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1329 if (mLooper == NULL) {
1330 mLooper = new ALooper;
1331 mLooper->start();
1332 }
1333 mRTSPController = new ARTSPController(mLooper);
1334 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001335
Andreas Huber7a747b82010-06-07 15:19:40 -07001336 LOGI("ARTSPController::connect returned %d", err);
1337
1338 if (err != OK) {
1339 mRTSPController.clear();
1340 return err;
1341 }
1342
1343 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001344 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001345 } else {
1346 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1347 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001348
1349 if (dataSource == NULL) {
1350 return UNKNOWN_ERROR;
1351 }
1352
1353 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1354
1355 if (extractor == NULL) {
1356 return UNKNOWN_ERROR;
1357 }
1358
Andreas Huberffdf4782010-02-09 14:05:43 -08001359 return setDataSource_l(extractor);
1360}
1361
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001362void AwesomePlayer::abortPrepare(status_t err) {
1363 CHECK(err != OK);
1364
1365 if (mIsAsyncPrepare) {
1366 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1367 }
1368
1369 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001370 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001371 mAsyncPrepareEvent = NULL;
1372 mPreparedCondition.broadcast();
1373}
1374
Andreas Huberf71daba2010-03-24 09:24:40 -07001375// static
1376bool AwesomePlayer::ContinuePreparation(void *cookie) {
1377 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1378
1379 return (me->mFlags & PREPARE_CANCELLED) == 0;
1380}
1381
Andreas Huber6be780e2010-02-08 14:40:30 -08001382void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001383 {
1384 Mutex::Autolock autoLock(mLock);
1385
Andreas Huberedbb4d82010-03-12 08:59:22 -08001386 if (mFlags & PREPARE_CANCELLED) {
1387 LOGI("prepare was cancelled before doing anything");
1388 abortPrepare(UNKNOWN_ERROR);
1389 return;
1390 }
1391
Andreas Huberffdf4782010-02-09 14:05:43 -08001392 if (mUri.size() > 0) {
1393 status_t err = finishSetDataSource_l();
1394
1395 if (err != OK) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001396 abortPrepare(err);
Andreas Huberffdf4782010-02-09 14:05:43 -08001397 return;
1398 }
1399 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001400
Andreas Huber55864df72010-03-08 12:28:22 -08001401 if (mVideoTrack != NULL && mVideoSource == NULL) {
1402 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001403
Andreas Huber55864df72010-03-08 12:28:22 -08001404 if (err != OK) {
1405 abortPrepare(err);
1406 return;
1407 }
1408 }
1409
1410 if (mAudioTrack != NULL && mAudioSource == NULL) {
1411 status_t err = initAudioDecoder();
1412
1413 if (err != OK) {
1414 abortPrepare(err);
1415 return;
1416 }
1417 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001418 }
1419
1420 Mutex::Autolock autoLock(mLock);
1421
Andreas Huberffdf4782010-02-09 14:05:43 -08001422 if (mIsAsyncPrepare) {
1423 if (mVideoWidth < 0 || mVideoHeight < 0) {
1424 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1425 } else {
1426 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1427 }
1428
1429 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001430 }
1431
Andreas Huberffdf4782010-02-09 14:05:43 -08001432 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001433 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001434 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001435 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001436 mPreparedCondition.broadcast();
Andreas Huber040301c2010-04-12 09:41:12 -07001437
1438 postBufferingEvent_l();
Andreas Huber6be780e2010-02-08 14:40:30 -08001439}
1440
Andreas Huberba7ec912010-02-12 10:42:02 -08001441status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001442 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001443 Mutex::Autolock autoLock(mLock);
1444
1445 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001446 if (mLastVideoBuffer == NULL) {
1447 //go into here if video is suspended again
1448 //after resuming without being played between
1449 //them
1450 SuspensionState *state = mSuspensionState;
1451 mSuspensionState = NULL;
1452 reset_l();
1453 mSuspensionState = state;
1454 return OK;
1455 }
1456
1457 delete mSuspensionState;
1458 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001459 }
1460
Andreas Huberedbb4d82010-03-12 08:59:22 -08001461 if (mFlags & PREPARING) {
1462 mFlags |= PREPARE_CANCELLED;
1463 if (mConnectingDataSource != NULL) {
1464 LOGI("interrupting the connection process");
1465 mConnectingDataSource->disconnect();
1466 }
1467 }
1468
Andreas Huberba7ec912010-02-12 10:42:02 -08001469 while (mFlags & PREPARING) {
1470 mPreparedCondition.wait(mLock);
1471 }
1472
1473 SuspensionState *state = new SuspensionState;
1474 state->mUri = mUri;
1475 state->mUriHeaders = mUriHeaders;
1476 state->mFileSource = mFileSource;
1477
Andreas Huber406a18b2010-02-18 16:45:13 -08001478 state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001479 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001480
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001481 if (mLastVideoBuffer) {
1482 size_t size = mLastVideoBuffer->range_length();
1483 if (size) {
1484 state->mLastVideoFrameSize = size;
1485 state->mLastVideoFrame = malloc(size);
1486 memcpy(state->mLastVideoFrame,
1487 (const uint8_t *)mLastVideoBuffer->data()
1488 + mLastVideoBuffer->range_offset(),
1489 size);
1490
1491 state->mVideoWidth = mVideoWidth;
1492 state->mVideoHeight = mVideoHeight;
1493
1494 sp<MetaData> meta = mVideoSource->getFormat();
1495 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1496 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1497 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1498 }
1499 }
1500
Andreas Huberba7ec912010-02-12 10:42:02 -08001501 reset_l();
1502
1503 mSuspensionState = state;
1504
1505 return OK;
1506}
1507
1508status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001509 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001510 Mutex::Autolock autoLock(mLock);
1511
1512 if (mSuspensionState == NULL) {
1513 return INVALID_OPERATION;
1514 }
1515
1516 SuspensionState *state = mSuspensionState;
1517 mSuspensionState = NULL;
1518
1519 status_t err;
1520 if (state->mFileSource != NULL) {
1521 err = setDataSource_l(state->mFileSource);
1522
1523 if (err == OK) {
1524 mFileSource = state->mFileSource;
1525 }
1526 } else {
1527 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1528 }
1529
1530 if (err != OK) {
1531 delete state;
1532 state = NULL;
1533
1534 return err;
1535 }
1536
1537 seekTo_l(state->mPositionUs);
1538
Andreas Huber406a18b2010-02-18 16:45:13 -08001539 mFlags = state->mFlags & (LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001540
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001541 if (state->mLastVideoFrame && mISurface != NULL) {
1542 mVideoRenderer =
1543 new AwesomeLocalRenderer(
1544 true, // previewOnly
1545 "",
1546 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1547 mISurface,
1548 state->mVideoWidth,
1549 state->mVideoHeight,
1550 state->mDecodedWidth,
1551 state->mDecodedHeight);
1552
1553 mVideoRendererIsPreview = true;
1554
1555 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1556 state->mLastVideoFrame, state->mLastVideoFrameSize);
1557 }
1558
Andreas Huberba7ec912010-02-12 10:42:02 -08001559 if (state->mFlags & PLAYING) {
1560 play_l();
1561 }
1562
Gloria Wangb19da8e2010-04-12 17:13:06 -07001563 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001564 state = NULL;
1565
1566 return OK;
1567}
1568
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001569uint32_t AwesomePlayer::flags() const {
1570 return mExtractorFlags;
1571}
1572
Andreas Huber27366fc2009-11-20 09:32:46 -08001573} // namespace android
1574