blob: 12022bd44f330db43a121886c74954b298d04140 [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
Andreas Huber87ab9cd2010-09-03 13:20:33 -070053static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
54static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
55
Andreas Huber27366fc2009-11-20 09:32:46 -080056struct AwesomeEvent : public TimedEventQueue::Event {
Andreas Huber6be780e2010-02-08 14:40:30 -080057 AwesomeEvent(
58 AwesomePlayer *player,
59 void (AwesomePlayer::*method)())
Andreas Huber27366fc2009-11-20 09:32:46 -080060 : mPlayer(player),
Andreas Huber6be780e2010-02-08 14:40:30 -080061 mMethod(method) {
Andreas Huber27366fc2009-11-20 09:32:46 -080062 }
63
64protected:
65 virtual ~AwesomeEvent() {}
66
67 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
Andreas Huber6be780e2010-02-08 14:40:30 -080068 (mPlayer->*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080069 }
70
71private:
72 AwesomePlayer *mPlayer;
Andreas Huber6be780e2010-02-08 14:40:30 -080073 void (AwesomePlayer::*mMethod)();
Andreas Huber27366fc2009-11-20 09:32:46 -080074
75 AwesomeEvent(const AwesomeEvent &);
76 AwesomeEvent &operator=(const AwesomeEvent &);
77};
78
Andreas Huber1314e732009-12-14 14:18:22 -080079struct AwesomeRemoteRenderer : public AwesomeRenderer {
80 AwesomeRemoteRenderer(const sp<IOMXRenderer> &target)
81 : mTarget(target) {
82 }
83
84 virtual void render(MediaBuffer *buffer) {
85 void *id;
86 if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
87 mTarget->render((IOMX::buffer_id)id);
88 }
89 }
90
91private:
92 sp<IOMXRenderer> mTarget;
93
94 AwesomeRemoteRenderer(const AwesomeRemoteRenderer &);
95 AwesomeRemoteRenderer &operator=(const AwesomeRemoteRenderer &);
96};
97
98struct AwesomeLocalRenderer : public AwesomeRenderer {
99 AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800100 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800101 const char *componentName,
Andreas Huber1314e732009-12-14 14:18:22 -0800102 OMX_COLOR_FORMATTYPE colorFormat,
103 const sp<ISurface> &surface,
104 size_t displayWidth, size_t displayHeight,
105 size_t decodedWidth, size_t decodedHeight)
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800106 : mTarget(NULL),
107 mLibHandle(NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800108 init(previewOnly, componentName,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800109 colorFormat, surface, displayWidth,
110 displayHeight, decodedWidth, decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800111 }
112
113 virtual void render(MediaBuffer *buffer) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800114 render((const uint8_t *)buffer->data() + buffer->range_offset(),
115 buffer->range_length());
116 }
117
118 void render(const void *data, size_t size) {
119 mTarget->render(data, size, NULL);
Andreas Huber1314e732009-12-14 14:18:22 -0800120 }
121
122protected:
123 virtual ~AwesomeLocalRenderer() {
124 delete mTarget;
125 mTarget = NULL;
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800126
127 if (mLibHandle) {
128 dlclose(mLibHandle);
129 mLibHandle = NULL;
130 }
Andreas Huber1314e732009-12-14 14:18:22 -0800131 }
132
133private:
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800134 VideoRenderer *mTarget;
135 void *mLibHandle;
136
137 void init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800138 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800139 const char *componentName,
140 OMX_COLOR_FORMATTYPE colorFormat,
141 const sp<ISurface> &surface,
142 size_t displayWidth, size_t displayHeight,
143 size_t decodedWidth, size_t decodedHeight);
Andreas Huber1314e732009-12-14 14:18:22 -0800144
145 AwesomeLocalRenderer(const AwesomeLocalRenderer &);
146 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
147};
148
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800149void AwesomeLocalRenderer::init(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800150 bool previewOnly,
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800151 const char *componentName,
152 OMX_COLOR_FORMATTYPE colorFormat,
153 const sp<ISurface> &surface,
154 size_t displayWidth, size_t displayHeight,
155 size_t decodedWidth, size_t decodedHeight) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800156 if (!previewOnly) {
157 // We will stick to the vanilla software-color-converting renderer
158 // for "previewOnly" mode, to avoid unneccessarily switching overlays
159 // more often than necessary.
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800160
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800161 mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800162
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800163 if (mLibHandle) {
164 typedef VideoRenderer *(*CreateRendererFunc)(
165 const sp<ISurface> &surface,
166 const char *componentName,
167 OMX_COLOR_FORMATTYPE colorFormat,
168 size_t displayWidth, size_t displayHeight,
169 size_t decodedWidth, size_t decodedHeight);
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800170
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800171 CreateRendererFunc func =
172 (CreateRendererFunc)dlsym(
173 mLibHandle,
174 "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
175 "OMX_COLOR_FORMATTYPEjjjj");
176
177 if (func) {
178 mTarget =
179 (*func)(surface, componentName, colorFormat,
180 displayWidth, displayHeight,
181 decodedWidth, decodedHeight);
182 }
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800183 }
184 }
185
186 if (mTarget == NULL) {
187 mTarget = new SoftwareRenderer(
188 colorFormat, surface, displayWidth, displayHeight,
189 decodedWidth, decodedHeight);
190 }
191}
192
Andreas Huber27366fc2009-11-20 09:32:46 -0800193AwesomePlayer::AwesomePlayer()
Andreas Huber406a18b2010-02-18 16:45:13 -0800194 : mQueueStarted(false),
195 mTimeSource(NULL),
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800196 mVideoRendererIsPreview(false),
Andreas Huber27366fc2009-11-20 09:32:46 -0800197 mAudioPlayer(NULL),
Andreas Huberffdf4782010-02-09 14:05:43 -0800198 mFlags(0),
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700199 mExtractorFlags(0),
Andreas Huber27366fc2009-11-20 09:32:46 -0800200 mLastVideoBuffer(NULL),
Andreas Huberba7ec912010-02-12 10:42:02 -0800201 mVideoBuffer(NULL),
202 mSuspensionState(NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800203 CHECK_EQ(mClient.connect(), OK);
204
205 DataSource::RegisterDefaultSniffers();
206
Andreas Huber6be780e2010-02-08 14:40:30 -0800207 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
Andreas Huber27366fc2009-11-20 09:32:46 -0800208 mVideoEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800209 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
Andreas Huber27366fc2009-11-20 09:32:46 -0800210 mStreamDoneEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800211 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
Andreas Huberb9e63832010-01-26 16:20:10 -0800212 mBufferingEventPending = false;
Andreas Huber6be780e2010-02-08 14:40:30 -0800213
214 mCheckAudioStatusEvent = new AwesomeEvent(
215 this, &AwesomePlayer::onCheckAudioStatus);
216
Andreas Huber70d10c02010-02-03 11:37:29 -0800217 mAudioStatusEventPending = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800218
Andreas Huber27366fc2009-11-20 09:32:46 -0800219 reset();
220}
221
222AwesomePlayer::~AwesomePlayer() {
Andreas Huber406a18b2010-02-18 16:45:13 -0800223 if (mQueueStarted) {
224 mQueue.stop();
225 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800226
227 reset();
228
229 mClient.disconnect();
230}
231
Andreas Huberb9e63832010-01-26 16:20:10 -0800232void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800233 mQueue.cancelEvent(mVideoEvent->eventID());
234 mVideoEventPending = false;
235 mQueue.cancelEvent(mStreamDoneEvent->eventID());
236 mStreamDoneEventPending = false;
Andreas Huber70d10c02010-02-03 11:37:29 -0800237 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID());
238 mAudioStatusEventPending = false;
Andreas Huberb9e63832010-01-26 16:20:10 -0800239
240 if (!keepBufferingGoing) {
241 mQueue.cancelEvent(mBufferingEvent->eventID());
242 mBufferingEventPending = false;
243 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800244}
245
Andreas Hubera3f43842010-01-21 10:28:45 -0800246void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800247 Mutex::Autolock autoLock(mLock);
248 mListener = listener;
249}
250
Andreas Huber433c9ac2010-01-27 16:49:05 -0800251status_t AwesomePlayer::setDataSource(
252 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800253 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800254 return setDataSource_l(uri, headers);
255}
Andreas Huber27366fc2009-11-20 09:32:46 -0800256
Andreas Huberba7ec912010-02-12 10:42:02 -0800257status_t AwesomePlayer::setDataSource_l(
258 const char *uri, const KeyedVector<String8, String8> *headers) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800259 reset_l();
260
Andreas Huberffdf4782010-02-09 14:05:43 -0800261 mUri = uri;
Andreas Huberb9e63832010-01-26 16:20:10 -0800262
Andreas Huberffdf4782010-02-09 14:05:43 -0800263 if (headers) {
264 mUriHeaders = *headers;
Andreas Huberb9e63832010-01-26 16:20:10 -0800265 }
266
Andreas Huberffdf4782010-02-09 14:05:43 -0800267 // The actual work will be done during preparation in the call to
268 // ::finishSetDataSource_l to avoid blocking the calling thread in
269 // setDataSource for any significant time.
Andreas Huber27366fc2009-11-20 09:32:46 -0800270
Andreas Huberffdf4782010-02-09 14:05:43 -0800271 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800272}
273
274status_t AwesomePlayer::setDataSource(
275 int fd, int64_t offset, int64_t length) {
Andreas Huber202348e2010-06-07 14:35:29 -0700276#if 0
Andreas Huber4dcc6a12010-09-01 12:22:36 -0700277 // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/sl.m3u8");
278 return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0440.m3u8");
279 // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0640.m3u8");
280 // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/1240_vod.m3u8");
Andreas Huber202348e2010-06-07 14:35:29 -0700281 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
282 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
Andreas Huber4dcc6a12010-09-01 12:22:36 -0700283 // return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
Andreas Huber202348e2010-06-07 14:35:29 -0700284 // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
285 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
286 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
287 // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/mtv/ni_spo_25a_rt74137_clip_syn/hi/prog_index.m3u8");
288#endif
289
Andreas Huber27366fc2009-11-20 09:32:46 -0800290 Mutex::Autolock autoLock(mLock);
291
292 reset_l();
293
Andreas Huberba7ec912010-02-12 10:42:02 -0800294 sp<DataSource> dataSource = new FileSource(fd, offset, length);
Andreas Huber27366fc2009-11-20 09:32:46 -0800295
Andreas Huberba7ec912010-02-12 10:42:02 -0800296 status_t err = dataSource->initCheck();
Andreas Huber27366fc2009-11-20 09:32:46 -0800297
298 if (err != OK) {
299 return err;
300 }
301
Andreas Huberba7ec912010-02-12 10:42:02 -0800302 mFileSource = dataSource;
303
304 return setDataSource_l(dataSource);
305}
306
307status_t AwesomePlayer::setDataSource_l(
308 const sp<DataSource> &dataSource) {
309 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
Andreas Huber27366fc2009-11-20 09:32:46 -0800310
311 if (extractor == NULL) {
312 return UNKNOWN_ERROR;
313 }
314
315 return setDataSource_l(extractor);
316}
317
318status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800319 bool haveAudio = false;
320 bool haveVideo = false;
321 for (size_t i = 0; i < extractor->countTracks(); ++i) {
322 sp<MetaData> meta = extractor->getTrackMetaData(i);
323
324 const char *mime;
325 CHECK(meta->findCString(kKeyMIMEType, &mime));
326
327 if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800328 setVideoSource(extractor->getTrack(i));
329 haveVideo = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800330 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800331 setAudioSource(extractor->getTrack(i));
332 haveAudio = true;
Andreas Huber9fee0b22010-09-03 14:09:21 -0700333
334 sp<MetaData> fileMeta = extractor->getMetaData();
335 int32_t loop;
336 if (fileMeta != NULL
337 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
338 mFlags |= AUTO_LOOPING;
339 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800340 }
341
342 if (haveAudio && haveVideo) {
343 break;
344 }
345 }
346
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700347 if (!haveAudio && !haveVideo) {
348 return UNKNOWN_ERROR;
349 }
350
351 mExtractorFlags = extractor->flags();
352
353 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800354}
355
356void AwesomePlayer::reset() {
357 Mutex::Autolock autoLock(mLock);
358 reset_l();
359}
360
361void AwesomePlayer::reset_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -0800362 if (mFlags & PREPARING) {
363 mFlags |= PREPARE_CANCELLED;
364 if (mConnectingDataSource != NULL) {
365 LOGI("interrupting the connection process");
366 mConnectingDataSource->disconnect();
367 }
368 }
369
Andreas Huberffdf4782010-02-09 14:05:43 -0800370 while (mFlags & PREPARING) {
371 mPreparedCondition.wait(mLock);
372 }
373
Andreas Huber27366fc2009-11-20 09:32:46 -0800374 cancelPlayerEvents();
375
Andreas Huber4d61f602010-06-10 11:17:50 -0700376 mCachedSource.clear();
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800377 mAudioTrack.clear();
378 mVideoTrack.clear();
379
Andreas Huberba7ec912010-02-12 10:42:02 -0800380 // Shutdown audio first, so that the respone to the reset request
381 // appears to happen instantaneously as far as the user is concerned
382 // If we did this later, audio would continue playing while we
383 // shutdown the video-related resources and the player appear to
384 // not be as responsive to a reset request.
Andreas Huberedbb4d82010-03-12 08:59:22 -0800385 if (mAudioPlayer == NULL && mAudioSource != NULL) {
386 // If we had an audio player, it would have effectively
387 // taken possession of the audio source and stopped it when
388 // _it_ is stopped. Otherwise this is still our responsibility.
389 mAudioSource->stop();
390 }
Andreas Huberba7ec912010-02-12 10:42:02 -0800391 mAudioSource.clear();
392
Andreas Huberba7ec912010-02-12 10:42:02 -0800393 mTimeSource = NULL;
394
395 delete mAudioPlayer;
396 mAudioPlayer = NULL;
397
Andreas Huber3522b5a52010-01-22 14:36:53 -0800398 mVideoRenderer.clear();
399
Andreas Huber27366fc2009-11-20 09:32:46 -0800400 if (mLastVideoBuffer) {
401 mLastVideoBuffer->release();
402 mLastVideoBuffer = NULL;
403 }
404
405 if (mVideoBuffer) {
406 mVideoBuffer->release();
407 mVideoBuffer = NULL;
408 }
409
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700410 if (mRTSPController != NULL) {
411 mRTSPController->disconnect();
412 mRTSPController.clear();
413 }
414
Andreas Huber57648e42010-08-04 10:14:30 -0700415 mRTPPusher.clear();
416 mRTCPPusher.clear();
417 mRTPSession.clear();
Andreas Huber7a747b82010-06-07 15:19:40 -0700418
Andreas Huber27366fc2009-11-20 09:32:46 -0800419 if (mVideoSource != NULL) {
420 mVideoSource->stop();
Andreas Huber98b48de2010-01-29 10:10:22 -0800421
422 // The following hack is necessary to ensure that the OMX
423 // component is completely released by the time we may try
424 // to instantiate it again.
425 wp<MediaSource> tmp = mVideoSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800426 mVideoSource.clear();
Andreas Huber98b48de2010-01-29 10:10:22 -0800427 while (tmp.promote() != NULL) {
428 usleep(1000);
429 }
430 IPCThreadState::self()->flushCommands();
Andreas Huber27366fc2009-11-20 09:32:46 -0800431 }
432
Andreas Huber27366fc2009-11-20 09:32:46 -0800433 mDurationUs = -1;
434 mFlags = 0;
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700435 mExtractorFlags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800436 mVideoWidth = mVideoHeight = -1;
437 mTimeSourceDeltaUs = 0;
438 mVideoTimeUs = 0;
439
440 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700441 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800442 mSeekTimeUs = 0;
Andreas Huberb9e63832010-01-26 16:20:10 -0800443
Andreas Huberffdf4782010-02-09 14:05:43 -0800444 mUri.setTo("");
445 mUriHeaders.clear();
Andreas Huberba7ec912010-02-12 10:42:02 -0800446
447 mFileSource.clear();
448
449 delete mSuspensionState;
450 mSuspensionState = NULL;
Andreas Huber27366fc2009-11-20 09:32:46 -0800451}
452
Andreas Huber6be780e2010-02-08 14:40:30 -0800453void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
Andreas Hubera3f43842010-01-21 10:28:45 -0800454 if (mListener != NULL) {
455 sp<MediaPlayerBase> listener = mListener.promote();
456
457 if (listener != NULL) {
Andreas Huber6be780e2010-02-08 14:40:30 -0800458 listener->sendEvent(msg, ext1, ext2);
Andreas Hubera3f43842010-01-21 10:28:45 -0800459 }
460 }
461}
462
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700463// Returns true iff cached duration is available/applicable.
464bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
465 off_t totalSize;
466
467 if (mRTSPController != NULL) {
468 *durationUs = mRTSPController->getQueueDurationUs(eos);
469 return true;
470 } else if (mCachedSource != NULL && mDurationUs >= 0
471 && mCachedSource->getSize(&totalSize) == OK) {
472 int64_t bitrate = totalSize * 8000000ll / mDurationUs; // in bits/sec
473
474 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
475 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
476 return true;
477 }
478
479 return false;
480}
481
Andreas Huberb9e63832010-01-26 16:20:10 -0800482void AwesomePlayer::onBufferingUpdate() {
483 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800484 if (!mBufferingEventPending) {
485 return;
486 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800487 mBufferingEventPending = false;
488
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700489 if (mCachedSource != NULL) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700490 bool eos;
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700491 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700492
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700493 if (eos) {
494 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
495 } else {
496 off_t size;
497 if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
498 int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700499
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700500 size_t cachedSize = mCachedSource->cachedSize();
501 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
502
503 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
504 if (percentage > 100) {
505 percentage = 100;
506 }
507
508 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
509 } else {
510 // We don't know the bitrate of the stream, use absolute size
511 // limits to maintain the cache.
512
513 const size_t kLowWaterMarkBytes = 400000;
514 const size_t kHighWaterMarkBytes = 1000000;
515
516 if ((mFlags & PLAYING) && !eos
517 && (cachedDataRemaining < kLowWaterMarkBytes)) {
518 LOGI("cache is running low (< %d) , pausing.",
519 kLowWaterMarkBytes);
520 mFlags |= CACHE_UNDERRUN;
521 pause_l();
522 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
523 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
524 if (mFlags & CACHE_UNDERRUN) {
525 LOGI("cache has filled up (> %d), resuming.",
526 kHighWaterMarkBytes);
527 mFlags &= ~CACHE_UNDERRUN;
528 play_l();
529 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
530 } else if (mFlags & PREPARING) {
531 LOGV("cache has filled up (> %d), prepare is done",
532 kHighWaterMarkBytes);
533 finishAsyncPrepare_l();
534 }
535 }
536 }
537 }
538 }
539
540 int64_t cachedDurationUs;
541 bool eos;
542 if (getCachedDuration_l(&cachedDurationUs, &eos)) {
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700543 if ((mFlags & PLAYING) && !eos
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700544 && (cachedDurationUs < kLowWaterMarkUs)) {
545 LOGI("cache is running low (%.2f secs) , pausing.",
546 cachedDurationUs / 1E6);
Andreas Huber4d8f66b2010-09-01 15:05:28 -0700547 mFlags |= CACHE_UNDERRUN;
548 pause_l();
549 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
Andreas Huber87ab9cd2010-09-03 13:20:33 -0700550 } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
551 if (mFlags & CACHE_UNDERRUN) {
552 LOGI("cache has filled up (%.2f secs), resuming.",
553 cachedDurationUs / 1E6);
554 mFlags &= ~CACHE_UNDERRUN;
555 play_l();
556 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
557 } else if (mFlags & PREPARING) {
558 LOGV("cache has filled up (%.2f secs), prepare is done",
559 cachedDurationUs / 1E6);
560 finishAsyncPrepare_l();
Andreas Huberc23296e2010-08-25 12:31:48 -0700561 }
Andreas Huberc23296e2010-08-25 12:31:48 -0700562 }
Andreas Huberb9e63832010-01-26 16:20:10 -0800563 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700564
Andreas Huber4d61f602010-06-10 11:17:50 -0700565 postBufferingEvent_l();
Andreas Huberb9e63832010-01-26 16:20:10 -0800566}
567
Andreas Huber27366fc2009-11-20 09:32:46 -0800568void AwesomePlayer::onStreamDone() {
569 // Posted whenever any stream finishes playing.
570
571 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -0800572 if (!mStreamDoneEventPending) {
573 return;
574 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800575 mStreamDoneEventPending = false;
576
Andreas Huber971305d2010-07-07 13:35:27 -0700577 if (mStreamDoneStatus != ERROR_END_OF_STREAM) {
578 LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
579
580 notifyListener_l(
581 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
582
583 pause_l();
584
585 mFlags |= AT_EOS;
586 return;
587 }
588
589 const bool allDone =
590 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS))
591 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS));
592
593 if (!allDone) {
594 return;
595 }
596
Andreas Huber9fee0b22010-09-03 14:09:21 -0700597 if (mFlags & (LOOPING | AUTO_LOOPING)) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800598 seekTo_l(0);
599
Andreas Huber7085b6842010-02-03 16:02:02 -0800600 if (mVideoSource != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800601 postVideoEvent_l();
602 }
603 } else {
Andreas Huber971305d2010-07-07 13:35:27 -0700604 LOGV("MEDIA_PLAYBACK_COMPLETE");
605 notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -0800606
607 pause_l();
Andreas Huber406a18b2010-02-18 16:45:13 -0800608
609 mFlags |= AT_EOS;
Andreas Huber27366fc2009-11-20 09:32:46 -0800610 }
611}
612
613status_t AwesomePlayer::play() {
614 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700615
616 mFlags &= ~CACHE_UNDERRUN;
617
Andreas Huberba7ec912010-02-12 10:42:02 -0800618 return play_l();
619}
Andreas Huber27366fc2009-11-20 09:32:46 -0800620
Andreas Huberba7ec912010-02-12 10:42:02 -0800621status_t AwesomePlayer::play_l() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800622 if (mFlags & PLAYING) {
623 return OK;
624 }
625
Andreas Huberffdf4782010-02-09 14:05:43 -0800626 if (!(mFlags & PREPARED)) {
627 status_t err = prepare_l();
628
629 if (err != OK) {
630 return err;
631 }
632 }
633
Andreas Huber27366fc2009-11-20 09:32:46 -0800634 mFlags |= PLAYING;
635 mFlags |= FIRST_FRAME;
636
Andreas Huberc1d5c922009-12-10 15:49:04 -0800637 bool deferredAudioSeek = false;
638
Andreas Huber27366fc2009-11-20 09:32:46 -0800639 if (mAudioSource != NULL) {
640 if (mAudioPlayer == NULL) {
641 if (mAudioSink != NULL) {
Andreas Huber2b359ed2010-09-28 11:56:39 -0700642 mAudioPlayer = new AudioPlayer(mAudioSink, this);
Andreas Huber27366fc2009-11-20 09:32:46 -0800643 mAudioPlayer->setSource(mAudioSource);
Andreas Huberdc9927d2010-03-08 15:46:13 -0800644
645 // We've already started the MediaSource in order to enable
646 // the prefetcher to read its data.
647 status_t err = mAudioPlayer->start(
648 true /* sourceAlreadyStarted */);
Andreas Huber62eac002010-01-29 13:24:58 -0800649
650 if (err != OK) {
651 delete mAudioPlayer;
652 mAudioPlayer = NULL;
653
654 mFlags &= ~(PLAYING | FIRST_FRAME);
655
656 return err;
657 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800658
Andreas Huber27366fc2009-11-20 09:32:46 -0800659 mTimeSource = mAudioPlayer;
660
Andreas Huberc1d5c922009-12-10 15:49:04 -0800661 deferredAudioSeek = true;
Andreas Huber70d10c02010-02-03 11:37:29 -0800662
663 mWatchForAudioSeekComplete = false;
664 mWatchForAudioEOS = true;
Andreas Huber27366fc2009-11-20 09:32:46 -0800665 }
666 } else {
667 mAudioPlayer->resume();
668 }
669 }
670
671 if (mTimeSource == NULL && mAudioPlayer == NULL) {
Andreas Huber971305d2010-07-07 13:35:27 -0700672 mTimeSource = &mSystemTimeSource;
Andreas Huber27366fc2009-11-20 09:32:46 -0800673 }
674
675 if (mVideoSource != NULL) {
Andreas Huber7085b6842010-02-03 16:02:02 -0800676 // Kick off video playback
677 postVideoEvent_l();
Andreas Huber27366fc2009-11-20 09:32:46 -0800678 }
679
Andreas Huberc1d5c922009-12-10 15:49:04 -0800680 if (deferredAudioSeek) {
681 // If there was a seek request while we were paused
682 // and we're just starting up again, honor the request now.
683 seekAudioIfNecessary_l();
684 }
685
Andreas Huber406a18b2010-02-18 16:45:13 -0800686 if (mFlags & AT_EOS) {
687 // Legacy behaviour, if a stream finishes playing and then
688 // is started again, we play from the start...
689 seekTo_l(0);
690 }
691
Andreas Huber27366fc2009-11-20 09:32:46 -0800692 return OK;
693}
694
695void AwesomePlayer::initRenderer_l() {
696 if (mISurface != NULL) {
697 sp<MetaData> meta = mVideoSource->getFormat();
698
699 int32_t format;
700 const char *component;
701 int32_t decodedWidth, decodedHeight;
702 CHECK(meta->findInt32(kKeyColorFormat, &format));
703 CHECK(meta->findCString(kKeyDecoderComponent, &component));
704 CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
705 CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
706
Andreas Hubera67d5382009-12-10 15:32:12 -0800707 mVideoRenderer.clear();
708
709 // Must ensure that mVideoRenderer's destructor is actually executed
710 // before creating a new one.
711 IPCThreadState::self()->flushCommands();
712
Andreas Huber1314e732009-12-14 14:18:22 -0800713 if (!strncmp("OMX.", component, 4)) {
714 // Our OMX codecs allocate buffers on the media_server side
715 // therefore they require a remote IOMXRenderer that knows how
716 // to display them.
717 mVideoRenderer = new AwesomeRemoteRenderer(
718 mClient.interface()->createRenderer(
719 mISurface, component,
720 (OMX_COLOR_FORMATTYPE)format,
721 decodedWidth, decodedHeight,
722 mVideoWidth, mVideoHeight));
723 } else {
724 // Other decoders are instantiated locally and as a consequence
725 // allocate their buffers in local address space.
726 mVideoRenderer = new AwesomeLocalRenderer(
Andreas Huber7b73cfc2010-02-12 14:40:08 -0800727 false, // previewOnly
Andreas Huber4ab5a6f2010-02-11 11:00:26 -0800728 component,
Andreas Huber1314e732009-12-14 14:18:22 -0800729 (OMX_COLOR_FORMATTYPE)format,
730 mISurface,
731 mVideoWidth, mVideoHeight,
732 decodedWidth, decodedHeight);
733 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800734 }
735}
736
737status_t AwesomePlayer::pause() {
738 Mutex::Autolock autoLock(mLock);
Andreas Huber4d61f602010-06-10 11:17:50 -0700739
740 mFlags &= ~CACHE_UNDERRUN;
741
Andreas Huber27366fc2009-11-20 09:32:46 -0800742 return pause_l();
743}
744
745status_t AwesomePlayer::pause_l() {
746 if (!(mFlags & PLAYING)) {
747 return OK;
748 }
749
Andreas Huberb9e63832010-01-26 16:20:10 -0800750 cancelPlayerEvents(true /* keepBufferingGoing */);
Andreas Huber27366fc2009-11-20 09:32:46 -0800751
752 if (mAudioPlayer != NULL) {
753 mAudioPlayer->pause();
754 }
755
756 mFlags &= ~PLAYING;
757
758 return OK;
759}
760
761bool AwesomePlayer::isPlaying() const {
Andreas Huber4d61f602010-06-10 11:17:50 -0700762 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
Andreas Huber27366fc2009-11-20 09:32:46 -0800763}
764
765void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
766 Mutex::Autolock autoLock(mLock);
767
768 mISurface = isurface;
769}
770
771void AwesomePlayer::setAudioSink(
772 const sp<MediaPlayerBase::AudioSink> &audioSink) {
773 Mutex::Autolock autoLock(mLock);
774
775 mAudioSink = audioSink;
776}
777
778status_t AwesomePlayer::setLooping(bool shouldLoop) {
779 Mutex::Autolock autoLock(mLock);
780
781 mFlags = mFlags & ~LOOPING;
782
783 if (shouldLoop) {
784 mFlags |= LOOPING;
785 }
786
787 return OK;
788}
789
790status_t AwesomePlayer::getDuration(int64_t *durationUs) {
Andreas Huber252573c2010-03-26 10:17:17 -0700791 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800792
793 if (mDurationUs < 0) {
794 return UNKNOWN_ERROR;
795 }
796
797 *durationUs = mDurationUs;
798
799 return OK;
800}
801
802status_t AwesomePlayer::getPosition(int64_t *positionUs) {
Andreas Hubereeb97d92010-08-27 13:29:08 -0700803 if (mRTSPController != NULL) {
804 *positionUs = mRTSPController->getNormalPlayTimeUs();
805 }
806 else if (mSeeking) {
Andreas Huberddb709c2010-04-07 10:24:35 -0700807 *positionUs = mSeekTimeUs;
808 } else if (mVideoSource != NULL) {
Andreas Huber252573c2010-03-26 10:17:17 -0700809 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800810 *positionUs = mVideoTimeUs;
811 } else if (mAudioPlayer != NULL) {
812 *positionUs = mAudioPlayer->getMediaTimeUs();
813 } else {
814 *positionUs = 0;
815 }
816
817 return OK;
818}
819
820status_t AwesomePlayer::seekTo(int64_t timeUs) {
Andreas Huber62f7ffe2010-05-06 10:18:05 -0700821 if (mExtractorFlags
822 & (MediaExtractor::CAN_SEEK_FORWARD
823 | MediaExtractor::CAN_SEEK_BACKWARD)) {
824 Mutex::Autolock autoLock(mLock);
825 return seekTo_l(timeUs);
826 }
827
828 return OK;
Andreas Huber27366fc2009-11-20 09:32:46 -0800829}
830
831status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700832 if (mRTSPController != NULL) {
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700833 mRTSPController->seek(timeUs);
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700834
835 notifyListener_l(MEDIA_SEEK_COMPLETE);
836 mSeekNotificationSent = true;
Andreas Hubere0dd7d32010-08-24 14:33:58 -0700837 return OK;
838 }
839
Andreas Huber4d61f602010-06-10 11:17:50 -0700840 if (mFlags & CACHE_UNDERRUN) {
841 mFlags &= ~CACHE_UNDERRUN;
842 play_l();
843 }
844
Andreas Huber27366fc2009-11-20 09:32:46 -0800845 mSeeking = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700846 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800847 mSeekTimeUs = timeUs;
Andreas Huber971305d2010-07-07 13:35:27 -0700848 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
Andreas Huber27366fc2009-11-20 09:32:46 -0800849
850 seekAudioIfNecessary_l();
851
Andreas Huber8e2b9412010-03-31 09:40:15 -0700852 if (!(mFlags & PLAYING)) {
853 LOGV("seeking while paused, sending SEEK_COMPLETE notification"
854 " immediately.");
855
856 notifyListener_l(MEDIA_SEEK_COMPLETE);
857 mSeekNotificationSent = true;
858 }
859
Andreas Huber27366fc2009-11-20 09:32:46 -0800860 return OK;
861}
862
863void AwesomePlayer::seekAudioIfNecessary_l() {
Andreas Huber7085b6842010-02-03 16:02:02 -0800864 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800865 mAudioPlayer->seekTo(mSeekTimeUs);
866
Andreas Huber70d10c02010-02-03 11:37:29 -0800867 mWatchForAudioSeekComplete = true;
868 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -0700869 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -0800870 }
871}
872
873status_t AwesomePlayer::getVideoDimensions(
874 int32_t *width, int32_t *height) const {
875 Mutex::Autolock autoLock(mLock);
876
877 if (mVideoWidth < 0 || mVideoHeight < 0) {
878 return UNKNOWN_ERROR;
879 }
880
881 *width = mVideoWidth;
882 *height = mVideoHeight;
883
884 return OK;
885}
886
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800887void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
888 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800889
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800890 mAudioTrack = source;
891}
892
893status_t AwesomePlayer::initAudioDecoder() {
894 sp<MetaData> meta = mAudioTrack->getFormat();
Andreas Huberc79827a2010-01-05 10:54:55 -0800895
896 const char *mime;
897 CHECK(meta->findCString(kKeyMIMEType, &mime));
898
899 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800900 mAudioSource = mAudioTrack;
Andreas Huberc79827a2010-01-05 10:54:55 -0800901 } else {
902 mAudioSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800903 mClient.interface(), mAudioTrack->getFormat(),
Andreas Huberc79827a2010-01-05 10:54:55 -0800904 false, // createEncoder
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800905 mAudioTrack);
Andreas Huberc79827a2010-01-05 10:54:55 -0800906 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800907
908 if (mAudioSource != NULL) {
909 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800910 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700911 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800912 if (mDurationUs < 0 || durationUs > mDurationUs) {
913 mDurationUs = durationUs;
914 }
915 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800916
Andreas Huber3c78a1b2010-05-13 09:15:21 -0700917 status_t err = mAudioSource->start();
918
919 if (err != OK) {
920 mAudioSource.clear();
921 return err;
922 }
Andreas Huberd0332ad2010-04-12 16:05:57 -0700923 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
924 // For legacy reasons we're simply going to ignore the absence
925 // of an audio decoder for QCELP instead of aborting playback
926 // altogether.
927 return OK;
928 }
Andreas Huberdc9927d2010-03-08 15:46:13 -0800929
Andreas Huber27366fc2009-11-20 09:32:46 -0800930 return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
931}
932
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800933void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
934 CHECK(source != NULL);
Andreas Huber27366fc2009-11-20 09:32:46 -0800935
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800936 mVideoTrack = source;
937}
938
939status_t AwesomePlayer::initVideoDecoder() {
Andreas Huber57648e42010-08-04 10:14:30 -0700940 uint32_t flags = 0;
Andreas Huber27366fc2009-11-20 09:32:46 -0800941 mVideoSource = OMXCodec::Create(
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800942 mClient.interface(), mVideoTrack->getFormat(),
Andreas Huber27366fc2009-11-20 09:32:46 -0800943 false, // createEncoder
Andreas Huber57648e42010-08-04 10:14:30 -0700944 mVideoTrack,
945 NULL, flags);
Andreas Huber27366fc2009-11-20 09:32:46 -0800946
947 if (mVideoSource != NULL) {
948 int64_t durationUs;
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800949 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Andreas Huber252573c2010-03-26 10:17:17 -0700950 Mutex::Autolock autoLock(mMiscStateLock);
Andreas Huber27366fc2009-11-20 09:32:46 -0800951 if (mDurationUs < 0 || durationUs > mDurationUs) {
952 mDurationUs = durationUs;
953 }
954 }
955
Andreas Huber3ac94ef2010-03-05 10:42:10 -0800956 CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
957 CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
Andreas Huber27366fc2009-11-20 09:32:46 -0800958
Andreas Huber1919e5a2010-05-20 10:37:06 -0700959 status_t err = mVideoSource->start();
960
961 if (err != OK) {
962 mVideoSource.clear();
963 return err;
964 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800965 }
966
967 return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
968}
969
Andreas Huber6be780e2010-02-08 14:40:30 -0800970void AwesomePlayer::onVideoEvent() {
Andreas Huber27366fc2009-11-20 09:32:46 -0800971 Mutex::Autolock autoLock(mLock);
Andreas Huberba7ec912010-02-12 10:42:02 -0800972 if (!mVideoEventPending) {
973 // The event has been cancelled in reset_l() but had already
974 // been scheduled for execution at that time.
975 return;
976 }
Andreas Huber27366fc2009-11-20 09:32:46 -0800977 mVideoEventPending = false;
978
979 if (mSeeking) {
980 if (mLastVideoBuffer) {
981 mLastVideoBuffer->release();
982 mLastVideoBuffer = NULL;
983 }
984
985 if (mVideoBuffer) {
986 mVideoBuffer->release();
987 mVideoBuffer = NULL;
988 }
Andreas Huber4d61f602010-06-10 11:17:50 -0700989
990 if (mCachedSource != NULL && mAudioSource != NULL) {
991 // We're going to seek the video source first, followed by
992 // the audio source.
993 // In order to avoid jumps in the DataSource offset caused by
994 // the audio codec prefetching data from the old locations
995 // while the video codec is already reading data from the new
996 // locations, we'll "pause" the audio source, causing it to
997 // stop reading input data until a subsequent seek.
998
999 if (mAudioPlayer != NULL) {
1000 mAudioPlayer->pause();
1001 }
1002 mAudioSource->pause();
1003 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001004 }
1005
1006 if (!mVideoBuffer) {
1007 MediaSource::ReadOptions options;
1008 if (mSeeking) {
1009 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
1010
Andreas Huber6624c9f2010-07-20 15:04:28 -07001011 options.setSeekTo(
1012 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
Andreas Huber27366fc2009-11-20 09:32:46 -08001013 }
1014 for (;;) {
1015 status_t err = mVideoSource->read(&mVideoBuffer, &options);
Andreas Huberb1f5ee42009-12-14 15:34:11 -08001016 options.clearSeekTo();
Andreas Huber27366fc2009-11-20 09:32:46 -08001017
1018 if (err != OK) {
1019 CHECK_EQ(mVideoBuffer, NULL);
1020
1021 if (err == INFO_FORMAT_CHANGED) {
1022 LOGV("VideoSource signalled format change.");
1023
Andreas Huber7085b6842010-02-03 16:02:02 -08001024 if (mVideoRenderer != NULL) {
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001025 mVideoRendererIsPreview = false;
Andreas Huber7085b6842010-02-03 16:02:02 -08001026 initRenderer_l();
1027 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001028 continue;
1029 }
1030
Andreas Huber971305d2010-07-07 13:35:27 -07001031 mFlags |= VIDEO_AT_EOS;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001032 postStreamDoneEvent_l(err);
Andreas Huber27366fc2009-11-20 09:32:46 -08001033 return;
1034 }
1035
Andreas Hubera67d5382009-12-10 15:32:12 -08001036 if (mVideoBuffer->range_length() == 0) {
Andreas Huber6ddcf012009-12-10 15:32:12 -08001037 // Some decoders, notably the PV AVC software decoder
1038 // return spurious empty buffers that we just want to ignore.
1039
Andreas Hubera67d5382009-12-10 15:32:12 -08001040 mVideoBuffer->release();
1041 mVideoBuffer = NULL;
1042 continue;
1043 }
1044
Andreas Huber27366fc2009-11-20 09:32:46 -08001045 break;
1046 }
1047 }
1048
1049 int64_t timeUs;
1050 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
1051
Andreas Huber252573c2010-03-26 10:17:17 -07001052 {
1053 Mutex::Autolock autoLock(mMiscStateLock);
1054 mVideoTimeUs = timeUs;
1055 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001056
1057 if (mSeeking) {
1058 if (mAudioPlayer != NULL) {
1059 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
1060
1061 mAudioPlayer->seekTo(timeUs);
Andreas Huber4d61f602010-06-10 11:17:50 -07001062 mAudioPlayer->resume();
Andreas Huber70d10c02010-02-03 11:37:29 -08001063 mWatchForAudioSeekComplete = true;
1064 mWatchForAudioEOS = true;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001065 } else if (!mSeekNotificationSent) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001066 // If we're playing video only, report seek complete now,
1067 // otherwise audio player will notify us later.
Andreas Hubera3f43842010-01-21 10:28:45 -08001068 notifyListener_l(MEDIA_SEEK_COMPLETE);
Andreas Huber27366fc2009-11-20 09:32:46 -08001069 }
1070
1071 mFlags |= FIRST_FRAME;
1072 mSeeking = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001073 mSeekNotificationSent = false;
Andreas Huber27366fc2009-11-20 09:32:46 -08001074 }
1075
Andreas Huber971305d2010-07-07 13:35:27 -07001076 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
1077
Andreas Huber27366fc2009-11-20 09:32:46 -08001078 if (mFlags & FIRST_FRAME) {
1079 mFlags &= ~FIRST_FRAME;
1080
Andreas Huber971305d2010-07-07 13:35:27 -07001081 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001082 }
1083
1084 int64_t realTimeUs, mediaTimeUs;
Andreas Huber971305d2010-07-07 13:35:27 -07001085 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
Andreas Huber27366fc2009-11-20 09:32:46 -08001086 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
1087 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
1088 }
1089
Andreas Huber971305d2010-07-07 13:35:27 -07001090 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
Andreas Huber27366fc2009-11-20 09:32:46 -08001091
1092 int64_t latenessUs = nowUs - timeUs;
1093
Andreas Huberf88f8442010-08-10 11:18:36 -07001094 if (mRTPSession != NULL) {
1095 // We'll completely ignore timestamps for gtalk videochat
1096 // and we'll play incoming video as fast as we get it.
1097 latenessUs = 0;
1098 }
1099
Andreas Huber24b0a952009-11-23 14:02:00 -08001100 if (latenessUs > 40000) {
1101 // We're more than 40ms late.
Andreas Huber4a9375e2010-02-09 11:54:33 -08001102 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
Andreas Huber27366fc2009-11-20 09:32:46 -08001103
1104 mVideoBuffer->release();
1105 mVideoBuffer = NULL;
1106
1107 postVideoEvent_l();
1108 return;
1109 }
1110
1111 if (latenessUs < -10000) {
1112 // We're more than 10ms early.
1113
1114 postVideoEvent_l(10000);
1115 return;
1116 }
1117
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001118 if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
1119 mVideoRendererIsPreview = false;
1120
Andreas Huber7085b6842010-02-03 16:02:02 -08001121 initRenderer_l();
1122 }
1123
1124 if (mVideoRenderer != NULL) {
1125 mVideoRenderer->render(mVideoBuffer);
1126 }
Andreas Huber27366fc2009-11-20 09:32:46 -08001127
1128 if (mLastVideoBuffer) {
1129 mLastVideoBuffer->release();
1130 mLastVideoBuffer = NULL;
1131 }
1132 mLastVideoBuffer = mVideoBuffer;
1133 mVideoBuffer = NULL;
1134
1135 postVideoEvent_l();
1136}
1137
1138void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
1139 if (mVideoEventPending) {
1140 return;
1141 }
1142
1143 mVideoEventPending = true;
1144 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
1145}
1146
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001147void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
Andreas Huber27366fc2009-11-20 09:32:46 -08001148 if (mStreamDoneEventPending) {
1149 return;
1150 }
1151 mStreamDoneEventPending = true;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001152
1153 mStreamDoneStatus = status;
Andreas Huber27366fc2009-11-20 09:32:46 -08001154 mQueue.postEvent(mStreamDoneEvent);
1155}
1156
Andreas Huberb9e63832010-01-26 16:20:10 -08001157void AwesomePlayer::postBufferingEvent_l() {
Andreas Huberb9e63832010-01-26 16:20:10 -08001158 if (mBufferingEventPending) {
1159 return;
1160 }
1161 mBufferingEventPending = true;
1162 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
1163}
1164
Andreas Huber70d10c02010-02-03 11:37:29 -08001165void AwesomePlayer::postCheckAudioStatusEvent_l() {
1166 if (mAudioStatusEventPending) {
1167 return;
1168 }
1169 mAudioStatusEventPending = true;
Andreas Huber2b359ed2010-09-28 11:56:39 -07001170 mQueue.postEvent(mCheckAudioStatusEvent);
Andreas Huber70d10c02010-02-03 11:37:29 -08001171}
1172
1173void AwesomePlayer::onCheckAudioStatus() {
1174 Mutex::Autolock autoLock(mLock);
Andreas Huberc0178f12010-02-17 15:58:57 -08001175 if (!mAudioStatusEventPending) {
1176 // Event was dispatched and while we were blocking on the mutex,
1177 // has already been cancelled.
1178 return;
1179 }
1180
Andreas Huber70d10c02010-02-03 11:37:29 -08001181 mAudioStatusEventPending = false;
1182
1183 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
1184 mWatchForAudioSeekComplete = false;
Andreas Huber8e2b9412010-03-31 09:40:15 -07001185
1186 if (!mSeekNotificationSent) {
1187 notifyListener_l(MEDIA_SEEK_COMPLETE);
1188 mSeekNotificationSent = true;
1189 }
Andreas Huberddb709c2010-04-07 10:24:35 -07001190
1191 mSeeking = false;
Andreas Huber70d10c02010-02-03 11:37:29 -08001192 }
1193
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001194 status_t finalStatus;
1195 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
Andreas Huber70d10c02010-02-03 11:37:29 -08001196 mWatchForAudioEOS = false;
Andreas Huber971305d2010-07-07 13:35:27 -07001197 mFlags |= AUDIO_AT_EOS;
1198 mFlags |= FIRST_FRAME;
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001199 postStreamDoneEvent_l(finalStatus);
Andreas Huber70d10c02010-02-03 11:37:29 -08001200 }
Andreas Huber70d10c02010-02-03 11:37:29 -08001201}
1202
Andreas Huber6be780e2010-02-08 14:40:30 -08001203status_t AwesomePlayer::prepare() {
1204 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001205 return prepare_l();
1206}
Andreas Huber6be780e2010-02-08 14:40:30 -08001207
Andreas Huberffdf4782010-02-09 14:05:43 -08001208status_t AwesomePlayer::prepare_l() {
1209 if (mFlags & PREPARED) {
1210 return OK;
1211 }
1212
1213 if (mFlags & PREPARING) {
1214 return UNKNOWN_ERROR;
1215 }
1216
1217 mIsAsyncPrepare = false;
Andreas Huber6be780e2010-02-08 14:40:30 -08001218 status_t err = prepareAsync_l();
1219
1220 if (err != OK) {
1221 return err;
1222 }
1223
Andreas Huberffdf4782010-02-09 14:05:43 -08001224 while (mFlags & PREPARING) {
Andreas Huber6be780e2010-02-08 14:40:30 -08001225 mPreparedCondition.wait(mLock);
1226 }
1227
Andreas Huberffdf4782010-02-09 14:05:43 -08001228 return mPrepareResult;
Andreas Huber6be780e2010-02-08 14:40:30 -08001229}
1230
1231status_t AwesomePlayer::prepareAsync() {
1232 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001233
1234 if (mFlags & PREPARING) {
1235 return UNKNOWN_ERROR; // async prepare already pending
1236 }
1237
1238 mIsAsyncPrepare = true;
Andreas Huber6be780e2010-02-08 14:40:30 -08001239 return prepareAsync_l();
1240}
1241
1242status_t AwesomePlayer::prepareAsync_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001243 if (mFlags & PREPARING) {
1244 return UNKNOWN_ERROR; // async prepare already pending
Andreas Huber6be780e2010-02-08 14:40:30 -08001245 }
1246
Andreas Huber406a18b2010-02-18 16:45:13 -08001247 if (!mQueueStarted) {
1248 mQueue.start();
1249 mQueueStarted = true;
1250 }
1251
Andreas Huberffdf4782010-02-09 14:05:43 -08001252 mFlags |= PREPARING;
Andreas Huber6be780e2010-02-08 14:40:30 -08001253 mAsyncPrepareEvent = new AwesomeEvent(
1254 this, &AwesomePlayer::onPrepareAsyncEvent);
1255
1256 mQueue.postEvent(mAsyncPrepareEvent);
1257
1258 return OK;
1259}
1260
Andreas Huberffdf4782010-02-09 14:05:43 -08001261status_t AwesomePlayer::finishSetDataSource_l() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001262 sp<DataSource> dataSource;
1263
1264 if (!strncasecmp("http://", mUri.string(), 7)) {
Andreas Huber4d61f602010-06-10 11:17:50 -07001265 mConnectingDataSource = new NuHTTPDataSource;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001266
1267 mLock.unlock();
Andreas Huber3a53dc52010-06-11 09:57:46 -07001268 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001269 mLock.lock();
1270
1271 if (err != OK) {
1272 mConnectingDataSource.clear();
1273
1274 LOGI("mConnectingDataSource->connect() returned %d", err);
1275 return err;
1276 }
1277
Andreas Huber4d61f602010-06-10 11:17:50 -07001278#if 0
1279 mCachedSource = new NuCachedSource2(
1280 new ThrottledSource(
1281 mConnectingDataSource, 50 * 1024 /* bytes/sec */));
1282#else
1283 mCachedSource = new NuCachedSource2(mConnectingDataSource);
1284#endif
Andreas Huberedbb4d82010-03-12 08:59:22 -08001285 mConnectingDataSource.clear();
Andreas Huber4d61f602010-06-10 11:17:50 -07001286
1287 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001288 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
1289 String8 uri("http://");
1290 uri.append(mUri.string() + 11);
1291
1292 dataSource = new LiveSource(uri.string());
1293
Andreas Huber4d61f602010-06-10 11:17:50 -07001294 mCachedSource = new NuCachedSource2(dataSource);
1295 dataSource = mCachedSource;
Andreas Huber202348e2010-06-07 14:35:29 -07001296
1297 sp<MediaExtractor> extractor =
1298 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
Andreas Huber4d61f602010-06-10 11:17:50 -07001299
1300 return setDataSource_l(extractor);
Mike Dodd8741dfa2010-08-12 16:04:35 -07001301 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
Andreas Huber57648e42010-08-04 10:14:30 -07001302 if (mLooper == NULL) {
1303 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001304 mLooper->setName("gtalk rtp");
Andreas Huber3eaa3002010-08-05 09:22:25 -07001305 mLooper->start(
1306 false /* runOnCallingThread */,
1307 false /* canCallJava */,
1308 PRIORITY_HIGHEST);
Andreas Huber57648e42010-08-04 10:14:30 -07001309 }
1310
Mike Dodd8741dfa2010-08-12 16:04:35 -07001311 const char *startOfCodecString = &mUri.string()[13];
1312 const char *startOfSlash1 = strchr(startOfCodecString, '/');
1313 if (startOfSlash1 == NULL) {
1314 return BAD_VALUE;
1315 }
1316 const char *startOfWidthString = &startOfSlash1[1];
1317 const char *startOfSlash2 = strchr(startOfWidthString, '/');
1318 if (startOfSlash2 == NULL) {
1319 return BAD_VALUE;
1320 }
1321 const char *startOfHeightString = &startOfSlash2[1];
1322
1323 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
1324 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
1325 String8 heightString(startOfHeightString);
1326
Andreas Huber57648e42010-08-04 10:14:30 -07001327#if 0
1328 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
1329 mLooper->registerHandler(mRTPPusher);
1330
1331 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435);
1332 mLooper->registerHandler(mRTCPPusher);
1333#endif
1334
1335 mRTPSession = new ARTPSession;
1336 mLooper->registerHandler(mRTPSession);
1337
1338#if 0
Andreas Huber57648e42010-08-04 10:14:30 -07001339 // My AMR SDP
1340 static const char *raw =
1341 "v=0\r\n"
1342 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1343 "s=QuickTime\r\n"
1344 "t=0 0\r\n"
1345 "a=range:npt=0-315\r\n"
1346 "a=isma-compliance:2,2.0,2\r\n"
1347 "m=audio 5434 RTP/AVP 97\r\n"
1348 "c=IN IP4 127.0.0.1\r\n"
1349 "b=AS:30\r\n"
1350 "a=rtpmap:97 AMR/8000/1\r\n"
1351 "a=fmtp:97 octet-align\r\n";
1352#elif 1
Mike Dodd8741dfa2010-08-12 16:04:35 -07001353 String8 sdp;
1354 sdp.appendFormat(
Andreas Huber57648e42010-08-04 10:14:30 -07001355 "v=0\r\n"
1356 "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
1357 "s=QuickTime\r\n"
1358 "t=0 0\r\n"
1359 "a=range:npt=0-315\r\n"
1360 "a=isma-compliance:2,2.0,2\r\n"
1361 "m=video 5434 RTP/AVP 97\r\n"
1362 "c=IN IP4 127.0.0.1\r\n"
1363 "b=AS:30\r\n"
Mike Dodd8741dfa2010-08-12 16:04:35 -07001364 "a=rtpmap:97 %s/90000\r\n"
1365 "a=cliprect:0,0,%s,%s\r\n"
1366 "a=framesize:97 %s-%s\r\n",
1367
1368 codecString.string(),
1369 heightString.string(), widthString.string(),
1370 widthString.string(), heightString.string()
1371 );
1372 const char *raw = sdp.string();
1373
Andreas Huber57648e42010-08-04 10:14:30 -07001374#endif
1375
1376 sp<ASessionDescription> desc = new ASessionDescription;
1377 CHECK(desc->setTo(raw, strlen(raw)));
1378
1379 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK);
1380
1381 if (mRTPPusher != NULL) {
1382 mRTPPusher->start();
1383 }
1384
1385 if (mRTCPPusher != NULL) {
1386 mRTCPPusher->start();
1387 }
1388
1389 CHECK_EQ(mRTPSession->countTracks(), 1u);
1390 sp<MediaSource> source = mRTPSession->trackAt(0);
1391
1392#if 0
1393 bool eos;
1394 while (((APacketSource *)source.get())
1395 ->getQueuedDuration(&eos) < 5000000ll && !eos) {
1396 usleep(100000ll);
1397 }
1398#endif
1399
1400 const char *mime;
1401 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
1402
1403 if (!strncasecmp("video/", mime, 6)) {
1404 setVideoSource(source);
1405 } else {
1406 CHECK(!strncasecmp("audio/", mime, 6));
1407 setAudioSource(source);
1408 }
1409
1410 mExtractorFlags = MediaExtractor::CAN_PAUSE;
1411
1412 return OK;
Andreas Huber7a747b82010-06-07 15:19:40 -07001413 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
1414 if (mLooper == NULL) {
1415 mLooper = new ALooper;
Andreas Huberc4e0b702010-08-27 15:21:07 -07001416 mLooper->setName("rtsp");
Andreas Huber7a747b82010-06-07 15:19:40 -07001417 mLooper->start();
1418 }
1419 mRTSPController = new ARTSPController(mLooper);
1420 status_t err = mRTSPController->connect(mUri.string());
Andreas Huber202348e2010-06-07 14:35:29 -07001421
Andreas Huber7a747b82010-06-07 15:19:40 -07001422 LOGI("ARTSPController::connect returned %d", err);
1423
1424 if (err != OK) {
1425 mRTSPController.clear();
1426 return err;
1427 }
1428
1429 sp<MediaExtractor> extractor = mRTSPController.get();
Andreas Huber202348e2010-06-07 14:35:29 -07001430 return setDataSource_l(extractor);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001431 } else {
1432 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
1433 }
Andreas Huberffdf4782010-02-09 14:05:43 -08001434
1435 if (dataSource == NULL) {
1436 return UNKNOWN_ERROR;
1437 }
1438
1439 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
1440
1441 if (extractor == NULL) {
1442 return UNKNOWN_ERROR;
1443 }
1444
Andreas Huberffdf4782010-02-09 14:05:43 -08001445 return setDataSource_l(extractor);
1446}
1447
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001448void AwesomePlayer::abortPrepare(status_t err) {
1449 CHECK(err != OK);
1450
1451 if (mIsAsyncPrepare) {
1452 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
1453 }
1454
1455 mPrepareResult = err;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001456 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huber3ac94ef2010-03-05 10:42:10 -08001457 mAsyncPrepareEvent = NULL;
1458 mPreparedCondition.broadcast();
1459}
1460
Andreas Huberf71daba2010-03-24 09:24:40 -07001461// static
1462bool AwesomePlayer::ContinuePreparation(void *cookie) {
1463 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
1464
1465 return (me->mFlags & PREPARE_CANCELLED) == 0;
1466}
1467
Andreas Huber6be780e2010-02-08 14:40:30 -08001468void AwesomePlayer::onPrepareAsyncEvent() {
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001469 Mutex::Autolock autoLock(mLock);
Andreas Huberffdf4782010-02-09 14:05:43 -08001470
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001471 if (mFlags & PREPARE_CANCELLED) {
1472 LOGI("prepare was cancelled before doing anything");
1473 abortPrepare(UNKNOWN_ERROR);
1474 return;
1475 }
1476
1477 if (mUri.size() > 0) {
1478 status_t err = finishSetDataSource_l();
1479
1480 if (err != OK) {
1481 abortPrepare(err);
Andreas Huberedbb4d82010-03-12 08:59:22 -08001482 return;
1483 }
Andreas Huber6be780e2010-02-08 14:40:30 -08001484 }
1485
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001486 if (mVideoTrack != NULL && mVideoSource == NULL) {
1487 status_t err = initVideoDecoder();
Andreas Huber6be780e2010-02-08 14:40:30 -08001488
Andreas Huber87ab9cd2010-09-03 13:20:33 -07001489 if (err != OK) {
1490 abortPrepare(err);
1491 return;
1492 }
1493 }
1494
1495 if (mAudioTrack != NULL && mAudioSource == NULL) {
1496 status_t err = initAudioDecoder();
1497
1498 if (err != OK) {
1499 abortPrepare(err);
1500 return;
1501 }
1502 }
1503
1504 if (mCachedSource != NULL || mRTSPController != NULL) {
1505 postBufferingEvent_l();
1506 } else {
1507 finishAsyncPrepare_l();
1508 }
1509}
1510
1511void AwesomePlayer::finishAsyncPrepare_l() {
Andreas Huberffdf4782010-02-09 14:05:43 -08001512 if (mIsAsyncPrepare) {
1513 if (mVideoWidth < 0 || mVideoHeight < 0) {
1514 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
1515 } else {
1516 notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
1517 }
1518
1519 notifyListener_l(MEDIA_PREPARED);
Andreas Huber6be780e2010-02-08 14:40:30 -08001520 }
1521
Andreas Huberffdf4782010-02-09 14:05:43 -08001522 mPrepareResult = OK;
Andreas Huberedbb4d82010-03-12 08:59:22 -08001523 mFlags &= ~(PREPARING|PREPARE_CANCELLED);
Andreas Huberffdf4782010-02-09 14:05:43 -08001524 mFlags |= PREPARED;
Andreas Huber6be780e2010-02-08 14:40:30 -08001525 mAsyncPrepareEvent = NULL;
Andreas Huberffdf4782010-02-09 14:05:43 -08001526 mPreparedCondition.broadcast();
Andreas Huber6be780e2010-02-08 14:40:30 -08001527}
1528
Andreas Huberba7ec912010-02-12 10:42:02 -08001529status_t AwesomePlayer::suspend() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001530 LOGV("suspend");
Andreas Huberba7ec912010-02-12 10:42:02 -08001531 Mutex::Autolock autoLock(mLock);
1532
1533 if (mSuspensionState != NULL) {
Gloria Wangb19da8e2010-04-12 17:13:06 -07001534 if (mLastVideoBuffer == NULL) {
1535 //go into here if video is suspended again
1536 //after resuming without being played between
1537 //them
1538 SuspensionState *state = mSuspensionState;
1539 mSuspensionState = NULL;
1540 reset_l();
1541 mSuspensionState = state;
1542 return OK;
1543 }
1544
1545 delete mSuspensionState;
1546 mSuspensionState = NULL;
Andreas Huberba7ec912010-02-12 10:42:02 -08001547 }
1548
Andreas Huberedbb4d82010-03-12 08:59:22 -08001549 if (mFlags & PREPARING) {
1550 mFlags |= PREPARE_CANCELLED;
1551 if (mConnectingDataSource != NULL) {
1552 LOGI("interrupting the connection process");
1553 mConnectingDataSource->disconnect();
1554 }
1555 }
1556
Andreas Huberba7ec912010-02-12 10:42:02 -08001557 while (mFlags & PREPARING) {
1558 mPreparedCondition.wait(mLock);
1559 }
1560
1561 SuspensionState *state = new SuspensionState;
1562 state->mUri = mUri;
1563 state->mUriHeaders = mUriHeaders;
1564 state->mFileSource = mFileSource;
1565
Andreas Huber9fee0b22010-09-03 14:09:21 -07001566 state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huber252573c2010-03-26 10:17:17 -07001567 getPosition(&state->mPositionUs);
Andreas Huberba7ec912010-02-12 10:42:02 -08001568
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001569 if (mLastVideoBuffer) {
1570 size_t size = mLastVideoBuffer->range_length();
1571 if (size) {
1572 state->mLastVideoFrameSize = size;
1573 state->mLastVideoFrame = malloc(size);
1574 memcpy(state->mLastVideoFrame,
1575 (const uint8_t *)mLastVideoBuffer->data()
1576 + mLastVideoBuffer->range_offset(),
1577 size);
1578
1579 state->mVideoWidth = mVideoWidth;
1580 state->mVideoHeight = mVideoHeight;
1581
1582 sp<MetaData> meta = mVideoSource->getFormat();
1583 CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
1584 CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
1585 CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
1586 }
1587 }
1588
Andreas Huberba7ec912010-02-12 10:42:02 -08001589 reset_l();
1590
1591 mSuspensionState = state;
1592
1593 return OK;
1594}
1595
1596status_t AwesomePlayer::resume() {
Andreas Huberedbb4d82010-03-12 08:59:22 -08001597 LOGV("resume");
Andreas Huberba7ec912010-02-12 10:42:02 -08001598 Mutex::Autolock autoLock(mLock);
1599
1600 if (mSuspensionState == NULL) {
1601 return INVALID_OPERATION;
1602 }
1603
1604 SuspensionState *state = mSuspensionState;
1605 mSuspensionState = NULL;
1606
1607 status_t err;
1608 if (state->mFileSource != NULL) {
1609 err = setDataSource_l(state->mFileSource);
1610
1611 if (err == OK) {
1612 mFileSource = state->mFileSource;
1613 }
1614 } else {
1615 err = setDataSource_l(state->mUri, &state->mUriHeaders);
1616 }
1617
1618 if (err != OK) {
1619 delete state;
1620 state = NULL;
1621
1622 return err;
1623 }
1624
1625 seekTo_l(state->mPositionUs);
1626
Andreas Huber9fee0b22010-09-03 14:09:21 -07001627 mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
Andreas Huberba7ec912010-02-12 10:42:02 -08001628
Andreas Huber7b73cfc2010-02-12 14:40:08 -08001629 if (state->mLastVideoFrame && mISurface != NULL) {
1630 mVideoRenderer =
1631 new AwesomeLocalRenderer(
1632 true, // previewOnly
1633 "",
1634 (OMX_COLOR_FORMATTYPE)state->mColorFormat,
1635 mISurface,
1636 state->mVideoWidth,
1637 state->mVideoHeight,
1638 state->mDecodedWidth,
1639 state->mDecodedHeight);
1640
1641 mVideoRendererIsPreview = true;
1642
1643 ((AwesomeLocalRenderer *)mVideoRenderer.get())->render(
1644 state->mLastVideoFrame, state->mLastVideoFrameSize);
1645 }
1646
Andreas Huberba7ec912010-02-12 10:42:02 -08001647 if (state->mFlags & PLAYING) {
1648 play_l();
1649 }
1650
Gloria Wangb19da8e2010-04-12 17:13:06 -07001651 mSuspensionState = state;
Andreas Huberba7ec912010-02-12 10:42:02 -08001652 state = NULL;
1653
1654 return OK;
1655}
1656
Andreas Huber62f7ffe2010-05-06 10:18:05 -07001657uint32_t AwesomePlayer::flags() const {
1658 return mExtractorFlags;
1659}
1660
Andreas Huber2b359ed2010-09-28 11:56:39 -07001661void AwesomePlayer::postAudioEOS() {
1662 postCheckAudioStatusEvent_l();
1663}
1664
1665void AwesomePlayer::postAudioSeekComplete() {
1666 postCheckAudioStatusEvent_l();
1667}
1668
Andreas Huber27366fc2009-11-20 09:32:46 -08001669} // namespace android
1670