blob: 469c9ca24549b3d99c6e31611daf169157f6fe05 [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),
40 mComponentName("decoder") {
41 // Every decoder has its own looper because MediaCodec operations
42 // are blocking, but NuPlayer needs asynchronous operations.
43 mDecoderLooper = new ALooper;
44 mDecoderLooper->setName("NuPlayerDecoder");
45 mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
46
47 mCodecLooper = new ALooper;
48 mCodecLooper->setName("NuPlayerDecoder-MC");
49 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
Andreas Huberf9334412010-12-15 15:17:42 -080050}
51
52NuPlayer::Decoder::~Decoder() {
53}
54
Lajos Molnar1cd13982014-01-17 15:12:51 -080055void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
Andreas Huberf9334412010-12-15 15:17:42 -080056 CHECK(mCodec == NULL);
Andreas Huberf9334412010-12-15 15:17:42 -080057
Lajos Molnar1cd13982014-01-17 15:12:51 -080058 ++mBufferGeneration;
59
Andreas Huber84066782011-08-16 09:34:26 -070060 AString mime;
61 CHECK(format->findString("mime", &mime));
Andreas Huberf9334412010-12-15 15:17:42 -080062
Lajos Molnar1cd13982014-01-17 15:12:51 -080063 sp<Surface> surface = NULL;
64 if (mNativeWindow != NULL) {
65 surface = mNativeWindow->getSurfaceTextureClient();
Andreas Huber84066782011-08-16 09:34:26 -070066 }
Andreas Huberf9334412010-12-15 15:17:42 -080067
Lajos Molnar1cd13982014-01-17 15:12:51 -080068 mComponentName = mime;
69 mComponentName.append(" decoder");
70 ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
71
72 mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
73 if (mCodec == NULL) {
74 ALOGE("Failed to create %s decoder", mime.c_str());
75 handleError(UNKNOWN_ERROR);
76 return;
77 }
78
79 mCodec->getName(&mComponentName);
80
Glenn Kasten11731182011-02-08 17:26:17 -080081 if (mNativeWindow != NULL) {
Lajos Molnar1cd13982014-01-17 15:12:51 -080082 // disconnect from surface as MediaCodec will reconnect
83 CHECK_EQ((int)NO_ERROR,
84 native_window_api_disconnect(
85 surface.get(),
86 NATIVE_WINDOW_API_MEDIA));
87 }
88 status_t err = mCodec->configure(
89 format, surface, NULL /* crypto */, 0 /* flags */);
90 if (err != OK) {
91 ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
92 handleError(err);
93 return;
94 }
95 // the following should work in configured state
96 CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
97 CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
98
99 err = mCodec->start();
100 if (err != OK) {
101 ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
102 handleError(err);
103 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800104 }
105
Lajos Molnar1cd13982014-01-17 15:12:51 -0800106 // the following should work after start
107 CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
108 CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
109 ALOGV("[%s] got %zu input and %zu output buffers",
110 mComponentName.c_str(),
111 mInputBuffers.size(),
112 mOutputBuffers.size());
Andreas Huber078cfcf2011-09-15 12:25:04 -0700113
Lajos Molnar1cd13982014-01-17 15:12:51 -0800114 requestCodecNotification();
115}
Andreas Huber078cfcf2011-09-15 12:25:04 -0700116
Lajos Molnar1cd13982014-01-17 15:12:51 -0800117void NuPlayer::Decoder::requestCodecNotification() {
118 if (mCodec != NULL) {
119 sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
120 reply->setInt32("generation", mBufferGeneration);
121 mCodec->requestActivityNotification(reply);
122 }
123}
124
125bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
126 int32_t generation;
127 CHECK(msg->findInt32("generation", &generation));
128 return generation != mBufferGeneration;
129}
130
131void NuPlayer::Decoder::init() {
132 mDecoderLooper->registerHandler(this);
133}
134
135void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
136 sp<AMessage> msg = new AMessage(kWhatConfigure, id());
137 msg->setMessage("format", format);
138 msg->post();
139}
140
141void NuPlayer::Decoder::handleError(int32_t err)
142{
143 sp<AMessage> notify = mNotify->dup();
144 notify->setInt32("what", kWhatError);
145 notify->setInt32("err", err);
146 notify->post();
147}
148
149bool NuPlayer::Decoder::handleAnInputBuffer() {
150 size_t bufferIx = -1;
151 status_t res = mCodec->dequeueInputBuffer(&bufferIx);
152 ALOGV("[%s] dequeued input: %d",
153 mComponentName.c_str(), res == OK ? (int)bufferIx : res);
154 if (res != OK) {
155 if (res != -EAGAIN) {
156 handleError(res);
157 }
158 return false;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700159 }
160
Lajos Molnar1cd13982014-01-17 15:12:51 -0800161 CHECK_LT(bufferIx, mInputBuffers.size());
Andreas Huberf9334412010-12-15 15:17:42 -0800162
Lajos Molnar1cd13982014-01-17 15:12:51 -0800163 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
164 reply->setSize("buffer-ix", bufferIx);
165 reply->setInt32("generation", mBufferGeneration);
166
167 sp<AMessage> notify = mNotify->dup();
168 notify->setInt32("what", kWhatFillThisBuffer);
169 notify->setBuffer("buffer", mInputBuffers[bufferIx]);
170 notify->setMessage("reply", reply);
171 notify->post();
172 return true;
173}
174
175void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
176 size_t bufferIx;
177 CHECK(msg->findSize("buffer-ix", &bufferIx));
178 CHECK_LT(bufferIx, mInputBuffers.size());
179 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
180
181 sp<ABuffer> buffer;
182 bool hasBuffer = msg->findBuffer("buffer", &buffer);
183 if (buffer == NULL /* includes !hasBuffer */) {
184 int32_t streamErr = ERROR_END_OF_STREAM;
185 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
186
187 if (streamErr == OK) {
188 /* buffers are returned to hold on to */
189 return;
190 }
191
192 // attempt to queue EOS
193 status_t err = mCodec->queueInputBuffer(
194 bufferIx,
195 0,
196 0,
197 0,
198 MediaCodec::BUFFER_FLAG_EOS);
199 if (streamErr == ERROR_END_OF_STREAM && err != OK) {
200 streamErr = err;
201 // err will not be ERROR_END_OF_STREAM
202 }
203
204 if (streamErr != ERROR_END_OF_STREAM) {
205 handleError(streamErr);
206 }
207 } else {
208 int64_t timeUs = 0;
209 uint32_t flags = 0;
210 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
211
212 int32_t eos;
213 // we do not expect CODECCONFIG or SYNCFRAME for decoder
214 if (buffer->meta()->findInt32("eos", &eos) && eos) {
215 flags |= MediaCodec::BUFFER_FLAG_EOS;
216 }
217
218 // copy into codec buffer
219 if (buffer != codecBuffer) {
220 CHECK_LE(buffer->size(), codecBuffer->capacity());
221 codecBuffer->setRange(0, buffer->size());
222 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
223 }
224
225 status_t err = mCodec->queueInputBuffer(
226 bufferIx,
227 codecBuffer->offset(),
228 codecBuffer->size(),
229 timeUs,
230 flags);
231 if (err != OK) {
232 ALOGE("Failed to queue input buffer for %s (err=%d)",
233 mComponentName.c_str(), err);
234 handleError(err);
235 }
236 }
237}
238
239bool NuPlayer::Decoder::handleAnOutputBuffer() {
240 size_t bufferIx = -1;
241 size_t offset;
242 size_t size;
243 int64_t timeUs;
244 uint32_t flags;
245 status_t res = mCodec->dequeueOutputBuffer(
246 &bufferIx, &offset, &size, &timeUs, &flags);
247
248 if (res != OK) {
249 ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
250 } else {
251 ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
252 mComponentName.c_str(), (int)bufferIx, timeUs, flags);
253 }
254
255 if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
256 res = mCodec->getOutputBuffers(&mOutputBuffers);
257 if (res != OK) {
258 ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
259 mComponentName.c_str(), res);
260 handleError(res);
261 return false;
262 }
263 // NuPlayer ignores this
264 return true;
265 } else if (res == INFO_FORMAT_CHANGED) {
266 sp<AMessage> format = new AMessage();
267 res = mCodec->getOutputFormat(&format);
268 if (res != OK) {
269 ALOGE("Failed to get output format for %s after INFO event (err=%d)",
270 mComponentName.c_str(), res);
271 handleError(res);
272 return false;
273 }
274
275 sp<AMessage> notify = mNotify->dup();
276 notify->setInt32("what", kWhatOutputFormatChanged);
277 notify->setMessage("format", format);
278 notify->post();
279 return true;
280 } else if (res == INFO_DISCONTINUITY) {
281 // nothing to do
282 return true;
283 } else if (res != OK) {
284 if (res != -EAGAIN) {
285 handleError(res);
286 }
287 return false;
288 }
289
290 CHECK_LT(bufferIx, mOutputBuffers.size());
291 sp<ABuffer> buffer = mOutputBuffers[bufferIx];
292 buffer->setRange(offset, size);
293 buffer->meta()->clear();
294 buffer->meta()->setInt64("timeUs", timeUs);
295 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
296 buffer->meta()->setInt32("eos", true);
297 }
298 // we do not expect CODECCONFIG or SYNCFRAME for decoder
299
300 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
301 reply->setSize("buffer-ix", bufferIx);
302 reply->setInt32("generation", mBufferGeneration);
303
304 sp<AMessage> notify = mNotify->dup();
305 notify->setInt32("what", kWhatDrainThisBuffer);
306 notify->setBuffer("buffer", buffer);
307 notify->setMessage("reply", reply);
308 notify->post();
309
310 // FIXME: This should be handled after rendering is complete,
311 // but Renderer needs it now
312 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
313 ALOGV("queueing eos [%s]", mComponentName.c_str());
314 sp<AMessage> notify = mNotify->dup();
315 notify->setInt32("what", kWhatEOS);
316 notify->setInt32("err", ERROR_END_OF_STREAM);
317 notify->post();
318 }
319 return true;
320}
321
322void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
323 status_t err;
324 int32_t render;
325 size_t bufferIx;
326 CHECK(msg->findSize("buffer-ix", &bufferIx));
327 if (msg->findInt32("render", &render) && render) {
328 err = mCodec->renderOutputBufferAndRelease(bufferIx);
329 } else {
330 err = mCodec->releaseOutputBuffer(bufferIx);
331 }
332 if (err != OK) {
333 ALOGE("failed to release output buffer for %s (err=%d)",
334 mComponentName.c_str(), err);
335 handleError(err);
336 }
337}
338
339void NuPlayer::Decoder::onFlush() {
340 status_t err = OK;
341 if (mCodec != NULL) {
342 err = mCodec->flush();
343 ++mBufferGeneration;
344 }
345
346 if (err != OK) {
347 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
348 handleError(err);
349 return;
350 }
351
352 sp<AMessage> notify = mNotify->dup();
353 notify->setInt32("what", kWhatFlushCompleted);
354 notify->post();
355}
356
357void NuPlayer::Decoder::onShutdown() {
358 status_t err = OK;
359 if (mCodec != NULL) {
360 err = mCodec->release();
361 mCodec = NULL;
362 ++mBufferGeneration;
363
364 if (mNativeWindow != NULL) {
365 // reconnect to surface as MediaCodec disconnected from it
366 CHECK_EQ((int)NO_ERROR,
367 native_window_api_connect(
368 mNativeWindow->getNativeWindow().get(),
369 NATIVE_WINDOW_API_MEDIA));
370 }
371 mComponentName = "decoder";
372 }
373
374 if (err != OK) {
375 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
376 handleError(err);
377 return;
378 }
379
380 sp<AMessage> notify = mNotify->dup();
381 notify->setInt32("what", kWhatShutdownCompleted);
382 notify->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800383}
384
385void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800386 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
387
Andreas Huberf9334412010-12-15 15:17:42 -0800388 switch (msg->what()) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800389 case kWhatConfigure:
390 {
391 sp<AMessage> format;
392 CHECK(msg->findMessage("format", &format));
393 onConfigure(format);
394 break;
395 }
396
Andreas Huberf9334412010-12-15 15:17:42 -0800397 case kWhatCodecNotify:
398 {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800399 if (!isStaleReply(msg)) {
400 while (handleAnInputBuffer()) {
401 }
Andreas Huberf9334412010-12-15 15:17:42 -0800402
Lajos Molnar1cd13982014-01-17 15:12:51 -0800403 while (handleAnOutputBuffer()) {
404 }
Andreas Huberf9334412010-12-15 15:17:42 -0800405 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800406
407 requestCodecNotification();
408 break;
409 }
410
411 case kWhatInputBufferFilled:
412 {
413 if (!isStaleReply(msg)) {
414 onInputBufferFilled(msg);
415 }
416 break;
417 }
418
419 case kWhatRenderBuffer:
420 {
421 if (!isStaleReply(msg)) {
422 onRenderBuffer(msg);
423 }
424 break;
425 }
426
427 case kWhatFlush:
428 {
429 onFlush();
430 break;
431 }
432
433 case kWhatShutdown:
434 {
435 onShutdown();
Andreas Huberf9334412010-12-15 15:17:42 -0800436 break;
437 }
438
439 default:
440 TRESPASS();
441 break;
442 }
443}
444
Andreas Huberf9334412010-12-15 15:17:42 -0800445void NuPlayer::Decoder::signalFlush() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800446 (new AMessage(kWhatFlush, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800447}
448
449void NuPlayer::Decoder::signalResume() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800450 // nothing to do
Andreas Huberf9334412010-12-15 15:17:42 -0800451}
452
Andreas Huber3831a062010-12-21 10:22:33 -0800453void NuPlayer::Decoder::initiateShutdown() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800454 (new AMessage(kWhatShutdown, id()))->post();
Andreas Huber3831a062010-12-21 10:22:33 -0800455}
456
Robert Shih6d0a94e2014-01-23 16:18:22 -0800457bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
458 if (targetFormat == NULL) {
459 return true;
460 }
461
462 AString mime;
463 if (!targetFormat->findString("mime", &mime)) {
464 return false;
465 }
466
467 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
468 // field-by-field comparison
469 const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
470 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
471 int32_t oldVal, newVal;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800472 if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
473 !targetFormat->findInt32(keys[i], &newVal) ||
474 oldVal != newVal) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800475 return false;
476 }
477 }
478
479 sp<ABuffer> oldBuf, newBuf;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800480 if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
481 targetFormat->findBuffer("csd-0", &newBuf)) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800482 if (oldBuf->size() != newBuf->size()) {
483 return false;
484 }
485 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
486 }
487 }
488 return false;
489}
490
491bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800492 if (mOutputFormat == NULL) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800493 return false;
494 }
495
496 if (targetFormat == NULL) {
497 return true;
498 }
499
500 AString oldMime, newMime;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800501 if (!mOutputFormat->findString("mime", &oldMime)
Robert Shih6d0a94e2014-01-23 16:18:22 -0800502 || !targetFormat->findString("mime", &newMime)
503 || !(oldMime == newMime)) {
504 return false;
505 }
506
507 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
508 bool seamless;
509 if (audio) {
510 seamless = supportsSeamlessAudioFormatChange(targetFormat);
511 } else {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800512 int32_t isAdaptive;
513 seamless = (mCodec != NULL &&
514 mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
515 isAdaptive);
Robert Shih6d0a94e2014-01-23 16:18:22 -0800516 }
517
518 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
519 return seamless;
520}
521
Andreas Huberf9334412010-12-15 15:17:42 -0800522} // namespace android
523