blob: d3dab1302eed5562603b2932c2c009e1d15cc55b [file] [log] [blame]
Andreas Huberf9334412010-12-15 15:17:42 -08001/*
2 * Copyright (C) 2010 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 "NuPlayer"
19#include <utils/Log.h>
20
21#include "NuPlayer.h"
22#include "NuPlayerDecoder.h"
23#include "NuPlayerRenderer.h"
24#include "NuPlayerStreamListener.h"
25
Andreas Huber3831a062010-12-21 10:22:33 -080026#include <media/stagefright/foundation/hexdump.h>
Andreas Huberf9334412010-12-15 15:17:42 -080027#include <media/stagefright/foundation/ABuffer.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/AMessage.h>
30#include <media/stagefright/ACodec.h>
31#include <media/stagefright/MediaErrors.h>
32#include <media/stagefright/MetaData.h>
33#include <surfaceflinger/Surface.h>
34
Andreas Huber3831a062010-12-21 10:22:33 -080035#define SHUTDOWN_ON_DISCONTINUITY 0
36
Andreas Huberf9334412010-12-15 15:17:42 -080037namespace android {
38
39////////////////////////////////////////////////////////////////////////////////
40
41NuPlayer::NuPlayer()
42 : mEOS(false),
43 mAudioEOS(false),
44 mVideoEOS(false),
45 mFlushingAudio(NONE),
46 mFlushingVideo(NONE) {
47}
48
49NuPlayer::~NuPlayer() {
50}
51
52void NuPlayer::setListener(const wp<MediaPlayerBase> &listener) {
53 mListener = listener;
54}
55
56void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
57 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
58
59 source->incStrong(this);
60 msg->setPointer("source", source.get()); // XXX unsafe.
61
62 msg->post();
63}
64
65void NuPlayer::setVideoSurface(const sp<Surface> &surface) {
66 sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, id());
67 msg->setObject("surface", surface);
68 msg->post();
69}
70
71void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) {
72 sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id());
73 msg->setObject("sink", sink);
74 msg->post();
75}
76
77void NuPlayer::start() {
78 (new AMessage(kWhatStart, id()))->post();
79}
80
81void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
82 switch (msg->what()) {
83 case kWhatSetDataSource:
84 {
85 LOGI("kWhatSetDataSource");
86
87 CHECK(mSource == NULL);
88
89 void *ptr;
90 CHECK(msg->findPointer("source", &ptr));
91
92 mSource = static_cast<IStreamSource *>(ptr);
93 mSource->decStrong(this);
94
95 mStreamListener = new NuPlayerStreamListener(mSource, id());
96 mTSParser = new ATSParser;
97 break;
98 }
99
100 case kWhatSetVideoSurface:
101 {
102 LOGI("kWhatSetVideoSurface");
103
104 sp<RefBase> obj;
105 CHECK(msg->findObject("surface", &obj));
106
107 mSurface = static_cast<Surface *>(obj.get());
108 break;
109 }
110
111 case kWhatSetAudioSink:
112 {
113 LOGI("kWhatSetAudioSink");
114
115 sp<RefBase> obj;
116 CHECK(msg->findObject("sink", &obj));
117
118 mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get());
119 break;
120 }
121
122 case kWhatStart:
123 {
124 mStreamListener->start();
125
126 mRenderer = new Renderer(
127 mAudioSink,
128 new AMessage(kWhatRendererNotify, id()));
129
130 looper()->registerHandler(mRenderer);
131
132 (new AMessage(kWhatScanSources, id()))->post();
133 break;
134 }
135
136 case kWhatScanSources:
137 {
Andreas Huber3831a062010-12-21 10:22:33 -0800138 instantiateDecoder(
139 false,
140 &mVideoDecoder,
141 false /* ignoreCodecSpecificData */);
Andreas Huberf9334412010-12-15 15:17:42 -0800142
143 if (mAudioSink != NULL) {
Andreas Huber3831a062010-12-21 10:22:33 -0800144 instantiateDecoder(
145 true,
146 &mAudioDecoder,
147 false /* ignoreCodecSpecificData */);
Andreas Huberf9334412010-12-15 15:17:42 -0800148 }
149
150 if (mEOS) {
151 break;
152 }
153
154 feedMoreTSData();
155
156 if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
157 msg->post(100000ll);
158 }
159 break;
160 }
161
162 case kWhatVideoNotify:
163 case kWhatAudioNotify:
164 {
165 bool audio = msg->what() == kWhatAudioNotify;
166
167 sp<AMessage> codecRequest;
168 CHECK(msg->findMessage("codec-request", &codecRequest));
169
170 int32_t what;
171 CHECK(codecRequest->findInt32("what", &what));
172
173 if (what == ACodec::kWhatFillThisBuffer) {
174 status_t err = feedDecoderInputData(
175 audio, codecRequest);
176
177 if (err == -EWOULDBLOCK && !mEOS) {
178 feedMoreTSData();
179 msg->post();
180 }
181 } else if (what == ACodec::kWhatEOS) {
182 mRenderer->queueEOS(audio, ERROR_END_OF_STREAM);
183 } else if (what == ACodec::kWhatFlushCompleted) {
184 if (audio) {
185 CHECK_EQ((int)mFlushingAudio, (int)FLUSHING_DECODER);
186 mFlushingAudio = FLUSHED;
187 } else {
188 CHECK_EQ((int)mFlushingVideo, (int)FLUSHING_DECODER);
189 mFlushingVideo = FLUSHED;
190 }
191
192 LOGI("decoder %s flush completed", audio ? "audio" : "video");
193
Andreas Huber3831a062010-12-21 10:22:33 -0800194#if SHUTDOWN_ON_DISCONTINUITY
195 LOGI("initiating %s decoder shutdown",
196 audio ? "audio" : "video");
Andreas Huberf9334412010-12-15 15:17:42 -0800197
Andreas Huber3831a062010-12-21 10:22:33 -0800198 (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown();
Andreas Huberf9334412010-12-15 15:17:42 -0800199
Andreas Huber3831a062010-12-21 10:22:33 -0800200 if (audio) {
201 mFlushingAudio = SHUTTING_DOWN_DECODER;
202 } else {
203 mFlushingVideo = SHUTTING_DOWN_DECODER;
Andreas Huberf9334412010-12-15 15:17:42 -0800204 }
Andreas Huber3831a062010-12-21 10:22:33 -0800205#endif
206
207 finishFlushIfPossible();
Andreas Huber2c2814b2010-12-15 17:18:20 -0800208 } else if (what == ACodec::kWhatOutputFormatChanged) {
209 CHECK(audio);
210
211 int32_t numChannels;
212 CHECK(codecRequest->findInt32("channel-count", &numChannels));
213
214 int32_t sampleRate;
215 CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
216
217 LOGI("Audio output format changed to %d Hz, %d channels",
218 sampleRate, numChannels);
219
220 mAudioSink->close();
221 CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
222 mAudioSink->start();
Andreas Huber3831a062010-12-21 10:22:33 -0800223
224 mRenderer->signalAudioSinkChanged();
225 } else if (what == ACodec::kWhatShutdownCompleted) {
226 LOGI("%s shutdown completed", audio ? "audio" : "video");
227 if (audio) {
228 mAudioDecoder.clear();
229
230 CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
231 mFlushingAudio = SHUT_DOWN;
232 } else {
233 mVideoDecoder.clear();
234
235 CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
236 mFlushingVideo = SHUT_DOWN;
237 }
238
239 finishFlushIfPossible();
Andreas Huberf9334412010-12-15 15:17:42 -0800240 } else {
241 CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer);
242
243 renderBuffer(audio, codecRequest);
244 }
245
246 break;
247 }
248
249 case kWhatRendererNotify:
250 {
251 int32_t what;
252 CHECK(msg->findInt32("what", &what));
253
254 if (what == Renderer::kWhatEOS) {
255 int32_t audio;
256 CHECK(msg->findInt32("audio", &audio));
257
258 if (audio) {
259 mAudioEOS = true;
260 } else {
261 mVideoEOS = true;
262 }
263
264 LOGI("reached %s EOS", audio ? "audio" : "video");
265
266 if ((mAudioEOS || mAudioDecoder == NULL)
267 && (mVideoEOS || mVideoDecoder == NULL)) {
268 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
269 }
270 } else {
271 CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete);
272
273 int32_t audio;
274 CHECK(msg->findInt32("audio", &audio));
275
276 LOGI("renderer %s flush completed.", audio ? "audio" : "video");
277 }
278 break;
279 }
280
281 case kWhatMoreDataQueued:
282 {
283 break;
284 }
285
286 default:
287 TRESPASS();
288 break;
289 }
290}
291
Andreas Huber3831a062010-12-21 10:22:33 -0800292void NuPlayer::finishFlushIfPossible() {
293 if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) {
294 return;
295 }
296
297 if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) {
298 return;
299 }
300
301 LOGI("both audio and video are flushed now.");
302
303 mRenderer->signalTimeDiscontinuity();
304
305 if (mFlushingAudio == SHUT_DOWN) {
306 instantiateDecoder(
307 true,
308 &mAudioDecoder,
309 true /* ignoreCodecSpecificData */);
310 CHECK(mAudioDecoder != NULL);
311 } else if (mAudioDecoder != NULL) {
312 mAudioDecoder->signalResume();
313 }
314
315 if (mFlushingVideo == SHUT_DOWN) {
316 instantiateDecoder(
317 false,
318 &mVideoDecoder,
319 true /* ignoreCodecSpecificData */);
320 CHECK(mVideoDecoder != NULL);
321 } else if (mVideoDecoder != NULL) {
322 mVideoDecoder->signalResume();
323 }
324
325 mFlushingAudio = NONE;
326 mFlushingVideo = NONE;
327}
328
Andreas Huberf9334412010-12-15 15:17:42 -0800329void NuPlayer::feedMoreTSData() {
330 CHECK(!mEOS);
331
332 for (int32_t i = 0; i < 10; ++i) {
333 char buffer[188];
334 ssize_t n = mStreamListener->read(buffer, sizeof(buffer));
335
336 if (n == 0) {
337 LOGI("input data EOS reached.");
338 mTSParser->signalEOS(ERROR_END_OF_STREAM);
339 mEOS = true;
340 break;
341 } else if (n == INFO_DISCONTINUITY) {
342 mTSParser->signalDiscontinuity(ATSParser::DISCONTINUITY_SEEK);
343 } else if (n < 0) {
344 CHECK_EQ(n, -EWOULDBLOCK);
345 break;
346 } else {
347 if (buffer[0] == 0x00) {
348 // XXX legacy
Andreas Huber3831a062010-12-21 10:22:33 -0800349 mTSParser->signalDiscontinuity(
350 buffer[1] == 0x00
351 ? ATSParser::DISCONTINUITY_SEEK
352 : ATSParser::DISCONTINUITY_FORMATCHANGE);
Andreas Huberf9334412010-12-15 15:17:42 -0800353 } else {
354 mTSParser->feedTSPacket(buffer, sizeof(buffer));
355 }
356 }
357 }
358}
359
360status_t NuPlayer::dequeueNextAccessUnit(
361 ATSParser::SourceType *type, sp<ABuffer> *accessUnit) {
362 accessUnit->clear();
363
364 status_t audioErr = -EWOULDBLOCK;
365 int64_t audioTimeUs;
366
367 sp<AnotherPacketSource> audioSource =
368 static_cast<AnotherPacketSource *>(
369 mTSParser->getSource(ATSParser::MPEG2ADTS_AUDIO).get());
370
371 if (audioSource != NULL) {
372 audioErr = audioSource->nextBufferTime(&audioTimeUs);
373 }
374
375 status_t videoErr = -EWOULDBLOCK;
376 int64_t videoTimeUs;
377
378 sp<AnotherPacketSource> videoSource =
379 static_cast<AnotherPacketSource *>(
380 mTSParser->getSource(ATSParser::AVC_VIDEO).get());
381
382 if (videoSource != NULL) {
383 videoErr = videoSource->nextBufferTime(&videoTimeUs);
384 }
385
386 if (audioErr == -EWOULDBLOCK || videoErr == -EWOULDBLOCK) {
387 return -EWOULDBLOCK;
388 }
389
390 if (audioErr != OK && videoErr != OK) {
391 return audioErr;
392 }
393
394 if (videoErr != OK || (audioErr == OK && audioTimeUs < videoTimeUs)) {
395 *type = ATSParser::MPEG2ADTS_AUDIO;
396 return audioSource->dequeueAccessUnit(accessUnit);
397 } else {
398 *type = ATSParser::AVC_VIDEO;
399 return videoSource->dequeueAccessUnit(accessUnit);
400 }
401}
402
403status_t NuPlayer::dequeueAccessUnit(
404 ATSParser::SourceType type, sp<ABuffer> *accessUnit) {
405 sp<AnotherPacketSource> source =
406 static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
407
408 if (source == NULL) {
409 return -EWOULDBLOCK;
410 }
411
412 status_t finalResult;
413 if (!source->hasBufferAvailable(&finalResult)) {
414 return finalResult == OK ? -EWOULDBLOCK : finalResult;
415 }
416
417 return source->dequeueAccessUnit(accessUnit);
418}
419
420status_t NuPlayer::instantiateDecoder(
Andreas Huber3831a062010-12-21 10:22:33 -0800421 bool audio, sp<Decoder> *decoder, bool ignoreCodecSpecificData) {
Andreas Huberf9334412010-12-15 15:17:42 -0800422 if (*decoder != NULL) {
423 return OK;
424 }
425
426 ATSParser::SourceType type =
427 audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
428
429 sp<AnotherPacketSource> source =
430 static_cast<AnotherPacketSource *>(
431 mTSParser->getSource(type).get());
432
433 if (source == NULL) {
434 return -EWOULDBLOCK;
435 }
436
437 sp<AMessage> notify =
438 new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
439 id());
440
441 *decoder = new Decoder(notify, audio ? NULL : mSurface);
442 looper()->registerHandler(*decoder);
443
444 const sp<MetaData> &meta = source->getFormat();
Andreas Huber3831a062010-12-21 10:22:33 -0800445 (*decoder)->configure(meta, ignoreCodecSpecificData);
Andreas Huberf9334412010-12-15 15:17:42 -0800446
Andreas Huberf9334412010-12-15 15:17:42 -0800447 return OK;
448}
449
450status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
451 sp<AMessage> reply;
452 CHECK(msg->findMessage("reply", &reply));
453
454 if ((audio && mFlushingAudio == FLUSHING_DECODER)
455 || (!audio && mFlushingVideo == FLUSHING_DECODER)) {
456 reply->setInt32("err", INFO_DISCONTINUITY);
457 reply->post();
458 return OK;
459 }
460
461 sp<ABuffer> accessUnit;
462 status_t err = dequeueAccessUnit(
463 audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO,
464 &accessUnit);
465
466 if (err == -EWOULDBLOCK) {
467 return err;
468 } else if (err != OK) {
469 if (err == INFO_DISCONTINUITY) {
470 LOGI("%s discontinuity", audio ? "audio" : "video");
471 (audio ? mAudioDecoder : mVideoDecoder)->signalFlush();
472 mRenderer->flush(audio);
473
474 if (audio) {
475 CHECK(mFlushingAudio == NONE
476 || mFlushingAudio == AWAITING_DISCONTINUITY);
477 mFlushingAudio = FLUSHING_DECODER;
478 if (mFlushingVideo == NONE) {
479 mFlushingVideo = (mVideoDecoder != NULL)
480 ? AWAITING_DISCONTINUITY
481 : FLUSHED;
482 }
483 } else {
484 CHECK(mFlushingVideo == NONE
485 || mFlushingVideo == AWAITING_DISCONTINUITY);
486 mFlushingVideo = FLUSHING_DECODER;
487 if (mFlushingAudio == NONE) {
488 mFlushingAudio = (mAudioDecoder != NULL)
489 ? AWAITING_DISCONTINUITY
490 : FLUSHED;
491 }
492 }
493 }
494
495 reply->setInt32("err", err);
496 reply->post();
497 return OK;
498 }
499
500 LOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
501
502#if 0
503 int64_t mediaTimeUs;
504 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
505 LOGI("feeding %s input buffer at media time %.2f secs",
506 audio ? "audio" : "video",
507 mediaTimeUs / 1E6);
508#endif
509
510 reply->setObject("buffer", accessUnit);
511 reply->post();
512
513 return OK;
514}
515
516void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
517 LOGV("renderBuffer %s", audio ? "audio" : "video");
518
519 sp<AMessage> reply;
520 CHECK(msg->findMessage("reply", &reply));
521
522 sp<RefBase> obj;
523 CHECK(msg->findObject("buffer", &obj));
524
525 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
526
527 mRenderer->queueBuffer(audio, buffer, reply);
528}
529
530void NuPlayer::notifyListener(int msg, int ext1, int ext2) {
531 if (mListener == NULL) {
532 return;
533 }
534
535 sp<MediaPlayerBase> listener = mListener.promote();
536
537 if (listener == NULL) {
538 return;
539 }
540
541 listener->sendEvent(msg, ext1, ext2);
542}
543
544} // namespace android