blob: cfbf2826f5b722210a94540e201f5706bbc4ee67 [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 "NuPlayerDecoder"
19#include <utils/Log.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080020#include <inttypes.h>
Andreas Huberf9334412010-12-15 15:17:42 -080021
22#include "NuPlayerDecoder.h"
23
Lajos Molnar1cd13982014-01-17 15:12:51 -080024#include <media/ICrypto.h>
Andreas Huberf9334412010-12-15 15:17:42 -080025#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080027#include <media/stagefright/foundation/AMessage.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080028#include <media/stagefright/MediaCodec.h>
Andreas Huberf9334412010-12-15 15:17:42 -080029#include <media/stagefright/MediaDefs.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080030#include <media/stagefright/MediaErrors.h>
Andreas Huberf9334412010-12-15 15:17:42 -080031
32namespace android {
33
34NuPlayer::Decoder::Decoder(
Glenn Kasten11731182011-02-08 17:26:17 -080035 const sp<AMessage> &notify,
36 const sp<NativeWindowWrapper> &nativeWindow)
Andreas Huberf9334412010-12-15 15:17:42 -080037 : mNotify(notify),
Lajos Molnar1cd13982014-01-17 15:12:51 -080038 mNativeWindow(nativeWindow),
39 mBufferGeneration(0),
Wei Jia704e7262014-06-04 16:21:56 -070040 mPaused(true),
Lajos Molnar1cd13982014-01-17 15:12:51 -080041 mComponentName("decoder") {
42 // Every decoder has its own looper because MediaCodec operations
43 // are blocking, but NuPlayer needs asynchronous operations.
44 mDecoderLooper = new ALooper;
45 mDecoderLooper->setName("NuPlayerDecoder");
46 mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
47
48 mCodecLooper = new ALooper;
49 mCodecLooper->setName("NuPlayerDecoder-MC");
50 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
Andreas Huberf9334412010-12-15 15:17:42 -080051}
52
53NuPlayer::Decoder::~Decoder() {
54}
55
Lajos Molnar1cd13982014-01-17 15:12:51 -080056void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
Andreas Huberf9334412010-12-15 15:17:42 -080057 CHECK(mCodec == NULL);
Andreas Huberf9334412010-12-15 15:17:42 -080058
Lajos Molnar1cd13982014-01-17 15:12:51 -080059 ++mBufferGeneration;
60
Andreas Huber84066782011-08-16 09:34:26 -070061 AString mime;
62 CHECK(format->findString("mime", &mime));
Andreas Huberf9334412010-12-15 15:17:42 -080063
Lajos Molnar1cd13982014-01-17 15:12:51 -080064 sp<Surface> surface = NULL;
65 if (mNativeWindow != NULL) {
66 surface = mNativeWindow->getSurfaceTextureClient();
Andreas Huber84066782011-08-16 09:34:26 -070067 }
Andreas Huberf9334412010-12-15 15:17:42 -080068
Lajos Molnar1cd13982014-01-17 15:12:51 -080069 mComponentName = mime;
70 mComponentName.append(" decoder");
71 ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
72
73 mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
74 if (mCodec == NULL) {
75 ALOGE("Failed to create %s decoder", mime.c_str());
76 handleError(UNKNOWN_ERROR);
77 return;
78 }
79
80 mCodec->getName(&mComponentName);
81
Glenn Kasten11731182011-02-08 17:26:17 -080082 if (mNativeWindow != NULL) {
Lajos Molnar1cd13982014-01-17 15:12:51 -080083 // disconnect from surface as MediaCodec will reconnect
84 CHECK_EQ((int)NO_ERROR,
85 native_window_api_disconnect(
86 surface.get(),
87 NATIVE_WINDOW_API_MEDIA));
88 }
89 status_t err = mCodec->configure(
90 format, surface, NULL /* crypto */, 0 /* flags */);
91 if (err != OK) {
92 ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
93 handleError(err);
94 return;
95 }
96 // the following should work in configured state
97 CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
98 CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
99
100 err = mCodec->start();
101 if (err != OK) {
102 ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
103 handleError(err);
104 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800105 }
106
Lajos Molnar1cd13982014-01-17 15:12:51 -0800107 // the following should work after start
108 CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
109 CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
110 ALOGV("[%s] got %zu input and %zu output buffers",
111 mComponentName.c_str(),
112 mInputBuffers.size(),
113 mOutputBuffers.size());
Andreas Huber078cfcf2011-09-15 12:25:04 -0700114
Lajos Molnar1cd13982014-01-17 15:12:51 -0800115 requestCodecNotification();
Wei Jia704e7262014-06-04 16:21:56 -0700116 mPaused = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800117}
Andreas Huber078cfcf2011-09-15 12:25:04 -0700118
Lajos Molnar1cd13982014-01-17 15:12:51 -0800119void NuPlayer::Decoder::requestCodecNotification() {
120 if (mCodec != NULL) {
121 sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
122 reply->setInt32("generation", mBufferGeneration);
123 mCodec->requestActivityNotification(reply);
124 }
125}
126
127bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
128 int32_t generation;
129 CHECK(msg->findInt32("generation", &generation));
130 return generation != mBufferGeneration;
131}
132
133void NuPlayer::Decoder::init() {
134 mDecoderLooper->registerHandler(this);
135}
136
137void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
138 sp<AMessage> msg = new AMessage(kWhatConfigure, id());
139 msg->setMessage("format", format);
140 msg->post();
141}
142
143void NuPlayer::Decoder::handleError(int32_t err)
144{
145 sp<AMessage> notify = mNotify->dup();
146 notify->setInt32("what", kWhatError);
147 notify->setInt32("err", err);
148 notify->post();
149}
150
151bool NuPlayer::Decoder::handleAnInputBuffer() {
152 size_t bufferIx = -1;
153 status_t res = mCodec->dequeueInputBuffer(&bufferIx);
154 ALOGV("[%s] dequeued input: %d",
155 mComponentName.c_str(), res == OK ? (int)bufferIx : res);
156 if (res != OK) {
157 if (res != -EAGAIN) {
158 handleError(res);
159 }
160 return false;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700161 }
162
Lajos Molnar1cd13982014-01-17 15:12:51 -0800163 CHECK_LT(bufferIx, mInputBuffers.size());
Andreas Huberf9334412010-12-15 15:17:42 -0800164
Lajos Molnar1cd13982014-01-17 15:12:51 -0800165 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
166 reply->setSize("buffer-ix", bufferIx);
167 reply->setInt32("generation", mBufferGeneration);
168
169 sp<AMessage> notify = mNotify->dup();
170 notify->setInt32("what", kWhatFillThisBuffer);
171 notify->setBuffer("buffer", mInputBuffers[bufferIx]);
172 notify->setMessage("reply", reply);
173 notify->post();
174 return true;
175}
176
177void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
178 size_t bufferIx;
179 CHECK(msg->findSize("buffer-ix", &bufferIx));
180 CHECK_LT(bufferIx, mInputBuffers.size());
181 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
182
183 sp<ABuffer> buffer;
184 bool hasBuffer = msg->findBuffer("buffer", &buffer);
185 if (buffer == NULL /* includes !hasBuffer */) {
186 int32_t streamErr = ERROR_END_OF_STREAM;
187 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
188
189 if (streamErr == OK) {
190 /* buffers are returned to hold on to */
191 return;
192 }
193
194 // attempt to queue EOS
195 status_t err = mCodec->queueInputBuffer(
196 bufferIx,
197 0,
198 0,
199 0,
200 MediaCodec::BUFFER_FLAG_EOS);
201 if (streamErr == ERROR_END_OF_STREAM && err != OK) {
202 streamErr = err;
203 // err will not be ERROR_END_OF_STREAM
204 }
205
206 if (streamErr != ERROR_END_OF_STREAM) {
207 handleError(streamErr);
208 }
209 } else {
210 int64_t timeUs = 0;
211 uint32_t flags = 0;
212 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
213
214 int32_t eos;
215 // we do not expect CODECCONFIG or SYNCFRAME for decoder
216 if (buffer->meta()->findInt32("eos", &eos) && eos) {
217 flags |= MediaCodec::BUFFER_FLAG_EOS;
218 }
219
220 // copy into codec buffer
221 if (buffer != codecBuffer) {
222 CHECK_LE(buffer->size(), codecBuffer->capacity());
223 codecBuffer->setRange(0, buffer->size());
224 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
225 }
226
227 status_t err = mCodec->queueInputBuffer(
228 bufferIx,
229 codecBuffer->offset(),
230 codecBuffer->size(),
231 timeUs,
232 flags);
233 if (err != OK) {
234 ALOGE("Failed to queue input buffer for %s (err=%d)",
235 mComponentName.c_str(), err);
236 handleError(err);
237 }
238 }
239}
240
241bool NuPlayer::Decoder::handleAnOutputBuffer() {
242 size_t bufferIx = -1;
243 size_t offset;
244 size_t size;
245 int64_t timeUs;
246 uint32_t flags;
247 status_t res = mCodec->dequeueOutputBuffer(
248 &bufferIx, &offset, &size, &timeUs, &flags);
249
250 if (res != OK) {
251 ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
252 } else {
253 ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
254 mComponentName.c_str(), (int)bufferIx, timeUs, flags);
255 }
256
257 if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
258 res = mCodec->getOutputBuffers(&mOutputBuffers);
259 if (res != OK) {
260 ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
261 mComponentName.c_str(), res);
262 handleError(res);
263 return false;
264 }
265 // NuPlayer ignores this
266 return true;
267 } else if (res == INFO_FORMAT_CHANGED) {
268 sp<AMessage> format = new AMessage();
269 res = mCodec->getOutputFormat(&format);
270 if (res != OK) {
271 ALOGE("Failed to get output format for %s after INFO event (err=%d)",
272 mComponentName.c_str(), res);
273 handleError(res);
274 return false;
275 }
276
277 sp<AMessage> notify = mNotify->dup();
278 notify->setInt32("what", kWhatOutputFormatChanged);
279 notify->setMessage("format", format);
280 notify->post();
281 return true;
282 } else if (res == INFO_DISCONTINUITY) {
283 // nothing to do
284 return true;
285 } else if (res != OK) {
286 if (res != -EAGAIN) {
287 handleError(res);
288 }
289 return false;
290 }
291
292 CHECK_LT(bufferIx, mOutputBuffers.size());
293 sp<ABuffer> buffer = mOutputBuffers[bufferIx];
294 buffer->setRange(offset, size);
295 buffer->meta()->clear();
296 buffer->meta()->setInt64("timeUs", timeUs);
297 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
298 buffer->meta()->setInt32("eos", true);
299 }
300 // we do not expect CODECCONFIG or SYNCFRAME for decoder
301
302 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
303 reply->setSize("buffer-ix", bufferIx);
304 reply->setInt32("generation", mBufferGeneration);
305
306 sp<AMessage> notify = mNotify->dup();
307 notify->setInt32("what", kWhatDrainThisBuffer);
308 notify->setBuffer("buffer", buffer);
309 notify->setMessage("reply", reply);
310 notify->post();
311
312 // FIXME: This should be handled after rendering is complete,
313 // but Renderer needs it now
314 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
315 ALOGV("queueing eos [%s]", mComponentName.c_str());
316 sp<AMessage> notify = mNotify->dup();
317 notify->setInt32("what", kWhatEOS);
318 notify->setInt32("err", ERROR_END_OF_STREAM);
319 notify->post();
320 }
321 return true;
322}
323
324void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
325 status_t err;
326 int32_t render;
327 size_t bufferIx;
328 CHECK(msg->findSize("buffer-ix", &bufferIx));
329 if (msg->findInt32("render", &render) && render) {
330 err = mCodec->renderOutputBufferAndRelease(bufferIx);
331 } else {
332 err = mCodec->releaseOutputBuffer(bufferIx);
333 }
334 if (err != OK) {
335 ALOGE("failed to release output buffer for %s (err=%d)",
336 mComponentName.c_str(), err);
337 handleError(err);
338 }
339}
340
341void NuPlayer::Decoder::onFlush() {
342 status_t err = OK;
343 if (mCodec != NULL) {
344 err = mCodec->flush();
345 ++mBufferGeneration;
346 }
347
348 if (err != OK) {
349 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
350 handleError(err);
351 return;
352 }
353
354 sp<AMessage> notify = mNotify->dup();
355 notify->setInt32("what", kWhatFlushCompleted);
356 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700357 mPaused = true;
358}
359
360void NuPlayer::Decoder::onResume() {
361 mPaused = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800362}
363
364void NuPlayer::Decoder::onShutdown() {
365 status_t err = OK;
366 if (mCodec != NULL) {
367 err = mCodec->release();
368 mCodec = NULL;
369 ++mBufferGeneration;
370
371 if (mNativeWindow != NULL) {
372 // reconnect to surface as MediaCodec disconnected from it
373 CHECK_EQ((int)NO_ERROR,
374 native_window_api_connect(
375 mNativeWindow->getNativeWindow().get(),
376 NATIVE_WINDOW_API_MEDIA));
377 }
378 mComponentName = "decoder";
379 }
380
381 if (err != OK) {
382 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
383 handleError(err);
384 return;
385 }
386
387 sp<AMessage> notify = mNotify->dup();
388 notify->setInt32("what", kWhatShutdownCompleted);
389 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700390 mPaused = true;
Andreas Huberf9334412010-12-15 15:17:42 -0800391}
392
393void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800394 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
395
Andreas Huberf9334412010-12-15 15:17:42 -0800396 switch (msg->what()) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800397 case kWhatConfigure:
398 {
399 sp<AMessage> format;
400 CHECK(msg->findMessage("format", &format));
401 onConfigure(format);
402 break;
403 }
404
Andreas Huberf9334412010-12-15 15:17:42 -0800405 case kWhatCodecNotify:
406 {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800407 if (!isStaleReply(msg)) {
Wei Jia704e7262014-06-04 16:21:56 -0700408 if (!mPaused) {
409 while (handleAnInputBuffer()) {
410 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800411 }
Andreas Huberf9334412010-12-15 15:17:42 -0800412
Lajos Molnar1cd13982014-01-17 15:12:51 -0800413 while (handleAnOutputBuffer()) {
414 }
Andreas Huberf9334412010-12-15 15:17:42 -0800415 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800416
417 requestCodecNotification();
418 break;
419 }
420
421 case kWhatInputBufferFilled:
422 {
423 if (!isStaleReply(msg)) {
424 onInputBufferFilled(msg);
425 }
426 break;
427 }
428
429 case kWhatRenderBuffer:
430 {
431 if (!isStaleReply(msg)) {
432 onRenderBuffer(msg);
433 }
434 break;
435 }
436
437 case kWhatFlush:
438 {
439 onFlush();
440 break;
441 }
442
Wei Jia704e7262014-06-04 16:21:56 -0700443 case kWhatResume:
444 {
445 onResume();
446 break;
447 }
448
Lajos Molnar1cd13982014-01-17 15:12:51 -0800449 case kWhatShutdown:
450 {
451 onShutdown();
Andreas Huberf9334412010-12-15 15:17:42 -0800452 break;
453 }
454
455 default:
456 TRESPASS();
457 break;
458 }
459}
460
Andreas Huberf9334412010-12-15 15:17:42 -0800461void NuPlayer::Decoder::signalFlush() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800462 (new AMessage(kWhatFlush, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800463}
464
465void NuPlayer::Decoder::signalResume() {
Wei Jia704e7262014-06-04 16:21:56 -0700466 (new AMessage(kWhatResume, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800467}
468
Andreas Huber3831a062010-12-21 10:22:33 -0800469void NuPlayer::Decoder::initiateShutdown() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800470 (new AMessage(kWhatShutdown, id()))->post();
Andreas Huber3831a062010-12-21 10:22:33 -0800471}
472
Robert Shih6d0a94e2014-01-23 16:18:22 -0800473bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
474 if (targetFormat == NULL) {
475 return true;
476 }
477
478 AString mime;
479 if (!targetFormat->findString("mime", &mime)) {
480 return false;
481 }
482
483 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
484 // field-by-field comparison
485 const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
486 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
487 int32_t oldVal, newVal;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800488 if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
489 !targetFormat->findInt32(keys[i], &newVal) ||
490 oldVal != newVal) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800491 return false;
492 }
493 }
494
495 sp<ABuffer> oldBuf, newBuf;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800496 if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
497 targetFormat->findBuffer("csd-0", &newBuf)) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800498 if (oldBuf->size() != newBuf->size()) {
499 return false;
500 }
501 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
502 }
503 }
504 return false;
505}
506
507bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800508 if (mOutputFormat == NULL) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800509 return false;
510 }
511
512 if (targetFormat == NULL) {
513 return true;
514 }
515
516 AString oldMime, newMime;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800517 if (!mOutputFormat->findString("mime", &oldMime)
Robert Shih6d0a94e2014-01-23 16:18:22 -0800518 || !targetFormat->findString("mime", &newMime)
519 || !(oldMime == newMime)) {
520 return false;
521 }
522
523 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
524 bool seamless;
525 if (audio) {
526 seamless = supportsSeamlessAudioFormatChange(targetFormat);
527 } else {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800528 int32_t isAdaptive;
529 seamless = (mCodec != NULL &&
530 mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
531 isAdaptive);
Robert Shih6d0a94e2014-01-23 16:18:22 -0800532 }
533
534 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
535 return seamless;
536}
537
Andreas Huberf9334412010-12-15 15:17:42 -0800538} // namespace android
539