blob: 8fce2f426e9bc7ce5b9c58dcab32b6b7b8dfd764 [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>
Chong Zhanga7fa1d92014-06-11 14:49:23 -070025#include <media/stagefright/foundation/ABitReader.h>
Andreas Huberf9334412010-12-15 15:17:42 -080026#include <media/stagefright/foundation/ABuffer.h>
27#include <media/stagefright/foundation/ADebug.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080028#include <media/stagefright/foundation/AMessage.h>
Lajos Molnar09524832014-07-17 14:29:51 -070029#include <media/stagefright/MediaBuffer.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080030#include <media/stagefright/MediaCodec.h>
Andreas Huberf9334412010-12-15 15:17:42 -080031#include <media/stagefright/MediaDefs.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080032#include <media/stagefright/MediaErrors.h>
Andreas Huberf9334412010-12-15 15:17:42 -080033
34namespace android {
35
36NuPlayer::Decoder::Decoder(
Glenn Kasten11731182011-02-08 17:26:17 -080037 const sp<AMessage> &notify,
38 const sp<NativeWindowWrapper> &nativeWindow)
Andreas Huberf9334412010-12-15 15:17:42 -080039 : mNotify(notify),
Lajos Molnar1cd13982014-01-17 15:12:51 -080040 mNativeWindow(nativeWindow),
41 mBufferGeneration(0),
Wei Jia704e7262014-06-04 16:21:56 -070042 mPaused(true),
Lajos Molnar1cd13982014-01-17 15:12:51 -080043 mComponentName("decoder") {
44 // Every decoder has its own looper because MediaCodec operations
45 // are blocking, but NuPlayer needs asynchronous operations.
46 mDecoderLooper = new ALooper;
47 mDecoderLooper->setName("NuPlayerDecoder");
48 mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
49
50 mCodecLooper = new ALooper;
51 mCodecLooper->setName("NuPlayerDecoder-MC");
52 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
Andreas Huberf9334412010-12-15 15:17:42 -080053}
54
55NuPlayer::Decoder::~Decoder() {
56}
57
Lajos Molnar09524832014-07-17 14:29:51 -070058static
59status_t PostAndAwaitResponse(
60 const sp<AMessage> &msg, sp<AMessage> *response) {
61 status_t err = msg->postAndAwaitResponse(response);
62
63 if (err != OK) {
64 return err;
65 }
66
67 if (!(*response)->findInt32("err", &err)) {
68 err = OK;
69 }
70
71 return err;
72}
73
Lajos Molnar1cd13982014-01-17 15:12:51 -080074void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
Andreas Huberf9334412010-12-15 15:17:42 -080075 CHECK(mCodec == NULL);
Andreas Huberf9334412010-12-15 15:17:42 -080076
Lajos Molnar1cd13982014-01-17 15:12:51 -080077 ++mBufferGeneration;
78
Andreas Huber84066782011-08-16 09:34:26 -070079 AString mime;
80 CHECK(format->findString("mime", &mime));
Andreas Huberf9334412010-12-15 15:17:42 -080081
Lajos Molnar1cd13982014-01-17 15:12:51 -080082 sp<Surface> surface = NULL;
83 if (mNativeWindow != NULL) {
84 surface = mNativeWindow->getSurfaceTextureClient();
Andreas Huber84066782011-08-16 09:34:26 -070085 }
Andreas Huberf9334412010-12-15 15:17:42 -080086
Lajos Molnar1cd13982014-01-17 15:12:51 -080087 mComponentName = mime;
88 mComponentName.append(" decoder");
89 ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
90
91 mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
Lajos Molnar09524832014-07-17 14:29:51 -070092 int32_t secure = 0;
93 if (format->findInt32("secure", &secure) && secure != 0) {
94 if (mCodec != NULL) {
95 mCodec->getName(&mComponentName);
96 mComponentName.append(".secure");
97 mCodec->release();
98 ALOGI("[%s] creating", mComponentName.c_str());
99 mCodec = MediaCodec::CreateByComponentName(
100 mCodecLooper, mComponentName.c_str());
101 }
102 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800103 if (mCodec == NULL) {
Lajos Molnar09524832014-07-17 14:29:51 -0700104 ALOGE("Failed to create %s%s decoder",
105 (secure ? "secure " : ""), mime.c_str());
Lajos Molnar1cd13982014-01-17 15:12:51 -0800106 handleError(UNKNOWN_ERROR);
107 return;
108 }
109
110 mCodec->getName(&mComponentName);
111
Glenn Kasten11731182011-02-08 17:26:17 -0800112 if (mNativeWindow != NULL) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800113 // disconnect from surface as MediaCodec will reconnect
114 CHECK_EQ((int)NO_ERROR,
115 native_window_api_disconnect(
116 surface.get(),
117 NATIVE_WINDOW_API_MEDIA));
118 }
119 status_t err = mCodec->configure(
120 format, surface, NULL /* crypto */, 0 /* flags */);
121 if (err != OK) {
122 ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
123 handleError(err);
124 return;
125 }
126 // the following should work in configured state
127 CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
128 CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
129
130 err = mCodec->start();
131 if (err != OK) {
132 ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
133 handleError(err);
134 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800135 }
136
Lajos Molnar1cd13982014-01-17 15:12:51 -0800137 // the following should work after start
138 CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
Lajos Molnar09524832014-07-17 14:29:51 -0700139 releaseAndResetMediaBuffers();
Lajos Molnar1cd13982014-01-17 15:12:51 -0800140 CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
141 ALOGV("[%s] got %zu input and %zu output buffers",
142 mComponentName.c_str(),
143 mInputBuffers.size(),
144 mOutputBuffers.size());
Andreas Huber078cfcf2011-09-15 12:25:04 -0700145
Lajos Molnar1cd13982014-01-17 15:12:51 -0800146 requestCodecNotification();
Wei Jia704e7262014-06-04 16:21:56 -0700147 mPaused = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800148}
Andreas Huber078cfcf2011-09-15 12:25:04 -0700149
Lajos Molnar09524832014-07-17 14:29:51 -0700150void NuPlayer::Decoder::releaseAndResetMediaBuffers() {
151 for (size_t i = 0; i < mMediaBuffers.size(); i++) {
152 if (mMediaBuffers[i] != NULL) {
153 mMediaBuffers[i]->release();
154 mMediaBuffers.editItemAt(i) = NULL;
155 }
156 }
157 mMediaBuffers.resize(mInputBuffers.size());
Wei Jia81e50d02014-07-24 10:28:47 -0700158 for (size_t i = 0; i < mMediaBuffers.size(); i++) {
159 mMediaBuffers.editItemAt(i) = NULL;
160 }
Lajos Molnar09524832014-07-17 14:29:51 -0700161 mInputBufferIsDequeued.clear();
162 mInputBufferIsDequeued.resize(mInputBuffers.size());
Wei Jia81e50d02014-07-24 10:28:47 -0700163 for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
164 mInputBufferIsDequeued.editItemAt(i) = false;
165 }
Lajos Molnar09524832014-07-17 14:29:51 -0700166}
167
Lajos Molnar1cd13982014-01-17 15:12:51 -0800168void NuPlayer::Decoder::requestCodecNotification() {
169 if (mCodec != NULL) {
170 sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
171 reply->setInt32("generation", mBufferGeneration);
172 mCodec->requestActivityNotification(reply);
173 }
174}
175
176bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
177 int32_t generation;
178 CHECK(msg->findInt32("generation", &generation));
179 return generation != mBufferGeneration;
180}
181
182void NuPlayer::Decoder::init() {
183 mDecoderLooper->registerHandler(this);
184}
185
186void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
187 sp<AMessage> msg = new AMessage(kWhatConfigure, id());
188 msg->setMessage("format", format);
189 msg->post();
190}
191
Lajos Molnar09524832014-07-17 14:29:51 -0700192status_t NuPlayer::Decoder::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
193 sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id());
194 msg->setPointer("buffers", buffers);
195
196 sp<AMessage> response;
197 return PostAndAwaitResponse(msg, &response);
198}
199
Lajos Molnar1cd13982014-01-17 15:12:51 -0800200void NuPlayer::Decoder::handleError(int32_t err)
201{
202 sp<AMessage> notify = mNotify->dup();
203 notify->setInt32("what", kWhatError);
204 notify->setInt32("err", err);
205 notify->post();
206}
207
208bool NuPlayer::Decoder::handleAnInputBuffer() {
209 size_t bufferIx = -1;
210 status_t res = mCodec->dequeueInputBuffer(&bufferIx);
211 ALOGV("[%s] dequeued input: %d",
212 mComponentName.c_str(), res == OK ? (int)bufferIx : res);
213 if (res != OK) {
214 if (res != -EAGAIN) {
215 handleError(res);
216 }
217 return false;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700218 }
219
Lajos Molnar1cd13982014-01-17 15:12:51 -0800220 CHECK_LT(bufferIx, mInputBuffers.size());
Andreas Huberf9334412010-12-15 15:17:42 -0800221
Lajos Molnar09524832014-07-17 14:29:51 -0700222 if (mMediaBuffers[bufferIx] != NULL) {
223 mMediaBuffers[bufferIx]->release();
224 mMediaBuffers.editItemAt(bufferIx) = NULL;
225 }
226 mInputBufferIsDequeued.editItemAt(bufferIx) = true;
227
Lajos Molnar1cd13982014-01-17 15:12:51 -0800228 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
229 reply->setSize("buffer-ix", bufferIx);
230 reply->setInt32("generation", mBufferGeneration);
231
232 sp<AMessage> notify = mNotify->dup();
233 notify->setInt32("what", kWhatFillThisBuffer);
234 notify->setBuffer("buffer", mInputBuffers[bufferIx]);
235 notify->setMessage("reply", reply);
236 notify->post();
237 return true;
238}
239
240void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
241 size_t bufferIx;
242 CHECK(msg->findSize("buffer-ix", &bufferIx));
243 CHECK_LT(bufferIx, mInputBuffers.size());
244 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
245
246 sp<ABuffer> buffer;
247 bool hasBuffer = msg->findBuffer("buffer", &buffer);
Lajos Molnar09524832014-07-17 14:29:51 -0700248
249 // handle widevine classic source - that fills an arbitrary input buffer
250 MediaBuffer *mediaBuffer = NULL;
251 if (hasBuffer && buffer->meta()->findPointer(
252 "mediaBuffer", (void **)&mediaBuffer)) {
253 if (mediaBuffer == NULL) {
254 // received no actual buffer
255 ALOGW("[%s] received null MediaBuffer %s",
256 mComponentName.c_str(), msg->debugString().c_str());
257 buffer = NULL;
258 } else {
259 // likely filled another buffer than we requested: adjust buffer index
260 size_t ix;
261 for (ix = 0; ix < mInputBuffers.size(); ix++) {
262 const sp<ABuffer> &buf = mInputBuffers[ix];
263 if (buf->data() == mediaBuffer->data()) {
264 // all input buffers are dequeued on start, hence the check
265 CHECK(mInputBufferIsDequeued[ix]);
266 ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
267 mComponentName.c_str(), ix, bufferIx);
268
269 // TRICKY: need buffer for the metadata, so instead, set
270 // codecBuffer to the same (though incorrect) buffer to
271 // avoid a memcpy into the codecBuffer
272 codecBuffer = buffer;
273 codecBuffer->setRange(
274 mediaBuffer->range_offset(),
275 mediaBuffer->range_length());
276 bufferIx = ix;
277 break;
278 }
279 }
280 CHECK(ix < mInputBuffers.size());
281 }
282 }
283
284 mInputBufferIsDequeued.editItemAt(bufferIx) = false;
285
Lajos Molnar1cd13982014-01-17 15:12:51 -0800286 if (buffer == NULL /* includes !hasBuffer */) {
287 int32_t streamErr = ERROR_END_OF_STREAM;
288 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
289
290 if (streamErr == OK) {
291 /* buffers are returned to hold on to */
292 return;
293 }
294
295 // attempt to queue EOS
296 status_t err = mCodec->queueInputBuffer(
297 bufferIx,
298 0,
299 0,
300 0,
301 MediaCodec::BUFFER_FLAG_EOS);
302 if (streamErr == ERROR_END_OF_STREAM && err != OK) {
303 streamErr = err;
304 // err will not be ERROR_END_OF_STREAM
305 }
306
307 if (streamErr != ERROR_END_OF_STREAM) {
308 handleError(streamErr);
309 }
310 } else {
311 int64_t timeUs = 0;
312 uint32_t flags = 0;
313 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
314
315 int32_t eos;
316 // we do not expect CODECCONFIG or SYNCFRAME for decoder
317 if (buffer->meta()->findInt32("eos", &eos) && eos) {
318 flags |= MediaCodec::BUFFER_FLAG_EOS;
319 }
320
321 // copy into codec buffer
322 if (buffer != codecBuffer) {
323 CHECK_LE(buffer->size(), codecBuffer->capacity());
324 codecBuffer->setRange(0, buffer->size());
325 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
326 }
327
328 status_t err = mCodec->queueInputBuffer(
329 bufferIx,
330 codecBuffer->offset(),
331 codecBuffer->size(),
332 timeUs,
333 flags);
334 if (err != OK) {
335 ALOGE("Failed to queue input buffer for %s (err=%d)",
336 mComponentName.c_str(), err);
337 handleError(err);
338 }
Lajos Molnar09524832014-07-17 14:29:51 -0700339
340 if (mediaBuffer != NULL) {
341 CHECK(mMediaBuffers[bufferIx] == NULL);
342 mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
343 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800344 }
345}
346
347bool NuPlayer::Decoder::handleAnOutputBuffer() {
348 size_t bufferIx = -1;
349 size_t offset;
350 size_t size;
351 int64_t timeUs;
352 uint32_t flags;
353 status_t res = mCodec->dequeueOutputBuffer(
354 &bufferIx, &offset, &size, &timeUs, &flags);
355
356 if (res != OK) {
357 ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
358 } else {
359 ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
360 mComponentName.c_str(), (int)bufferIx, timeUs, flags);
361 }
362
363 if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
364 res = mCodec->getOutputBuffers(&mOutputBuffers);
365 if (res != OK) {
366 ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
367 mComponentName.c_str(), res);
368 handleError(res);
369 return false;
370 }
371 // NuPlayer ignores this
372 return true;
373 } else if (res == INFO_FORMAT_CHANGED) {
374 sp<AMessage> format = new AMessage();
375 res = mCodec->getOutputFormat(&format);
376 if (res != OK) {
377 ALOGE("Failed to get output format for %s after INFO event (err=%d)",
378 mComponentName.c_str(), res);
379 handleError(res);
380 return false;
381 }
382
383 sp<AMessage> notify = mNotify->dup();
384 notify->setInt32("what", kWhatOutputFormatChanged);
385 notify->setMessage("format", format);
386 notify->post();
387 return true;
388 } else if (res == INFO_DISCONTINUITY) {
389 // nothing to do
390 return true;
391 } else if (res != OK) {
392 if (res != -EAGAIN) {
393 handleError(res);
394 }
395 return false;
396 }
397
398 CHECK_LT(bufferIx, mOutputBuffers.size());
399 sp<ABuffer> buffer = mOutputBuffers[bufferIx];
400 buffer->setRange(offset, size);
401 buffer->meta()->clear();
402 buffer->meta()->setInt64("timeUs", timeUs);
403 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
404 buffer->meta()->setInt32("eos", true);
405 }
406 // we do not expect CODECCONFIG or SYNCFRAME for decoder
407
408 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
409 reply->setSize("buffer-ix", bufferIx);
410 reply->setInt32("generation", mBufferGeneration);
411
412 sp<AMessage> notify = mNotify->dup();
413 notify->setInt32("what", kWhatDrainThisBuffer);
414 notify->setBuffer("buffer", buffer);
415 notify->setMessage("reply", reply);
416 notify->post();
417
418 // FIXME: This should be handled after rendering is complete,
419 // but Renderer needs it now
420 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
421 ALOGV("queueing eos [%s]", mComponentName.c_str());
422 sp<AMessage> notify = mNotify->dup();
423 notify->setInt32("what", kWhatEOS);
424 notify->setInt32("err", ERROR_END_OF_STREAM);
425 notify->post();
426 }
427 return true;
428}
429
430void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
431 status_t err;
432 int32_t render;
433 size_t bufferIx;
434 CHECK(msg->findSize("buffer-ix", &bufferIx));
435 if (msg->findInt32("render", &render) && render) {
436 err = mCodec->renderOutputBufferAndRelease(bufferIx);
437 } else {
438 err = mCodec->releaseOutputBuffer(bufferIx);
439 }
440 if (err != OK) {
441 ALOGE("failed to release output buffer for %s (err=%d)",
442 mComponentName.c_str(), err);
443 handleError(err);
444 }
445}
446
447void NuPlayer::Decoder::onFlush() {
448 status_t err = OK;
449 if (mCodec != NULL) {
450 err = mCodec->flush();
451 ++mBufferGeneration;
452 }
453
454 if (err != OK) {
455 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
456 handleError(err);
457 return;
458 }
459
Lajos Molnar09524832014-07-17 14:29:51 -0700460 releaseAndResetMediaBuffers();
461
Lajos Molnar1cd13982014-01-17 15:12:51 -0800462 sp<AMessage> notify = mNotify->dup();
463 notify->setInt32("what", kWhatFlushCompleted);
464 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700465 mPaused = true;
466}
467
468void NuPlayer::Decoder::onResume() {
469 mPaused = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800470}
471
472void NuPlayer::Decoder::onShutdown() {
473 status_t err = OK;
474 if (mCodec != NULL) {
475 err = mCodec->release();
476 mCodec = NULL;
477 ++mBufferGeneration;
478
479 if (mNativeWindow != NULL) {
480 // reconnect to surface as MediaCodec disconnected from it
481 CHECK_EQ((int)NO_ERROR,
482 native_window_api_connect(
483 mNativeWindow->getNativeWindow().get(),
484 NATIVE_WINDOW_API_MEDIA));
485 }
486 mComponentName = "decoder";
487 }
488
Lajos Molnar09524832014-07-17 14:29:51 -0700489 releaseAndResetMediaBuffers();
490
Lajos Molnar1cd13982014-01-17 15:12:51 -0800491 if (err != OK) {
492 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
493 handleError(err);
494 return;
495 }
496
497 sp<AMessage> notify = mNotify->dup();
498 notify->setInt32("what", kWhatShutdownCompleted);
499 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700500 mPaused = true;
Andreas Huberf9334412010-12-15 15:17:42 -0800501}
502
503void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800504 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
505
Andreas Huberf9334412010-12-15 15:17:42 -0800506 switch (msg->what()) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800507 case kWhatConfigure:
508 {
509 sp<AMessage> format;
510 CHECK(msg->findMessage("format", &format));
511 onConfigure(format);
512 break;
513 }
514
Lajos Molnar09524832014-07-17 14:29:51 -0700515 case kWhatGetInputBuffers:
516 {
517 uint32_t replyID;
518 CHECK(msg->senderAwaitsResponse(&replyID));
519
520 Vector<sp<ABuffer> > *dstBuffers;
521 CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
522
523 dstBuffers->clear();
524 for (size_t i = 0; i < mInputBuffers.size(); i++) {
525 dstBuffers->push(mInputBuffers[i]);
526 }
527
528 (new AMessage)->postReply(replyID);
529 break;
530 }
531
Andreas Huberf9334412010-12-15 15:17:42 -0800532 case kWhatCodecNotify:
533 {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800534 if (!isStaleReply(msg)) {
Wei Jia704e7262014-06-04 16:21:56 -0700535 if (!mPaused) {
536 while (handleAnInputBuffer()) {
537 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800538 }
Andreas Huberf9334412010-12-15 15:17:42 -0800539
Lajos Molnar1cd13982014-01-17 15:12:51 -0800540 while (handleAnOutputBuffer()) {
541 }
Andreas Huberf9334412010-12-15 15:17:42 -0800542 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800543
544 requestCodecNotification();
545 break;
546 }
547
548 case kWhatInputBufferFilled:
549 {
550 if (!isStaleReply(msg)) {
551 onInputBufferFilled(msg);
552 }
553 break;
554 }
555
556 case kWhatRenderBuffer:
557 {
558 if (!isStaleReply(msg)) {
559 onRenderBuffer(msg);
560 }
561 break;
562 }
563
564 case kWhatFlush:
565 {
566 onFlush();
567 break;
568 }
569
Wei Jia704e7262014-06-04 16:21:56 -0700570 case kWhatResume:
571 {
572 onResume();
573 break;
574 }
575
Lajos Molnar1cd13982014-01-17 15:12:51 -0800576 case kWhatShutdown:
577 {
578 onShutdown();
Andreas Huberf9334412010-12-15 15:17:42 -0800579 break;
580 }
581
582 default:
583 TRESPASS();
584 break;
585 }
586}
587
Andreas Huberf9334412010-12-15 15:17:42 -0800588void NuPlayer::Decoder::signalFlush() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800589 (new AMessage(kWhatFlush, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800590}
591
592void NuPlayer::Decoder::signalResume() {
Wei Jia704e7262014-06-04 16:21:56 -0700593 (new AMessage(kWhatResume, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800594}
595
Andreas Huber3831a062010-12-21 10:22:33 -0800596void NuPlayer::Decoder::initiateShutdown() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800597 (new AMessage(kWhatShutdown, id()))->post();
Andreas Huber3831a062010-12-21 10:22:33 -0800598}
599
Robert Shih6d0a94e2014-01-23 16:18:22 -0800600bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
601 if (targetFormat == NULL) {
602 return true;
603 }
604
605 AString mime;
606 if (!targetFormat->findString("mime", &mime)) {
607 return false;
608 }
609
610 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
611 // field-by-field comparison
612 const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
613 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
614 int32_t oldVal, newVal;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800615 if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
616 !targetFormat->findInt32(keys[i], &newVal) ||
617 oldVal != newVal) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800618 return false;
619 }
620 }
621
622 sp<ABuffer> oldBuf, newBuf;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800623 if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
624 targetFormat->findBuffer("csd-0", &newBuf)) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800625 if (oldBuf->size() != newBuf->size()) {
626 return false;
627 }
628 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
629 }
630 }
631 return false;
632}
633
634bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800635 if (mOutputFormat == NULL) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800636 return false;
637 }
638
639 if (targetFormat == NULL) {
640 return true;
641 }
642
643 AString oldMime, newMime;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800644 if (!mOutputFormat->findString("mime", &oldMime)
Robert Shih6d0a94e2014-01-23 16:18:22 -0800645 || !targetFormat->findString("mime", &newMime)
646 || !(oldMime == newMime)) {
647 return false;
648 }
649
650 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
651 bool seamless;
652 if (audio) {
653 seamless = supportsSeamlessAudioFormatChange(targetFormat);
654 } else {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800655 int32_t isAdaptive;
656 seamless = (mCodec != NULL &&
657 mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
658 isAdaptive);
Robert Shih6d0a94e2014-01-23 16:18:22 -0800659 }
660
661 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
662 return seamless;
663}
664
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700665struct NuPlayer::CCDecoder::CCData {
666 CCData(uint8_t type, uint8_t data1, uint8_t data2)
667 : mType(type), mData1(data1), mData2(data2) {
668 }
669
670 uint8_t mType;
671 uint8_t mData1;
672 uint8_t mData2;
673};
674
675NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
676 : mNotify(notify),
677 mTrackCount(0),
678 mSelectedTrack(-1) {
679}
680
681size_t NuPlayer::CCDecoder::getTrackCount() const {
682 return mTrackCount;
683}
684
685sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
686 CHECK(index == 0);
687
688 sp<AMessage> format = new AMessage();
689
690 format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
691 format->setString("language", "und");
692 format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
693 format->setInt32("auto", 1);
694 format->setInt32("default", 1);
695 format->setInt32("forced", 0);
696
697 return format;
698}
699
700status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
701 CHECK(index < mTrackCount);
702
703 if (select) {
704 if (mSelectedTrack == (ssize_t)index) {
705 ALOGE("track %zu already selected", index);
706 return BAD_VALUE;
707 }
708 ALOGV("selected track %zu", index);
709 mSelectedTrack = index;
710 } else {
711 if (mSelectedTrack != (ssize_t)index) {
712 ALOGE("track %zu is not selected", index);
713 return BAD_VALUE;
714 }
715 ALOGV("unselected track %zu", index);
716 mSelectedTrack = -1;
717 }
718
719 return OK;
720}
721
722bool NuPlayer::CCDecoder::isSelected() const {
723 return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount;
724}
725
726bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const {
727 return cc->mData1 < 0x10 && cc->mData2 < 0x10;
728}
729
730void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const {
731 size_t offset = 0;
732 AString out;
733
734 while (offset < ccBuf->size()) {
735 char tmp[128];
736
737 CCData *cc = (CCData *) (ccBuf->data() + offset);
738
739 if (isNullPad(cc)) {
740 // 1 null pad or XDS metadata, ignore
741 offset += sizeof(CCData);
742 continue;
743 }
744
745 if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
746 // 2 basic chars
747 sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
748 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
749 && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
750 // 1 special char
751 sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
752 } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
753 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
754 // 1 Spanish/French char
755 sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
756 } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
757 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
758 // 1 Portuguese/German/Danish char
759 sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
760 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
761 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
762 // Mid-Row Codes (Table 69)
763 sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
764 } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
765 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
766 ||
767 ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
768 && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
769 // Misc Control Codes (Table 70)
770 sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
771 } else if ((cc->mData1 & 0x70) == 0x10
772 && (cc->mData2 & 0x40) == 0x40
773 && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
774 // Preamble Address Codes (Table 71)
775 sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
776 } else {
777 sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
778 }
779
780 if (out.size() > 0) {
781 out.append(", ");
782 }
783
784 out.append(tmp);
785
786 offset += sizeof(CCData);
787 }
788
789 ALOGI("%s", out.c_str());
790}
791
792bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
793 int64_t timeUs;
794 CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
795
796 sp<ABuffer> sei;
797 if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
798 return false;
799 }
800
801 bool hasCC = false;
802
Chong Zhang862f8452014-06-26 19:55:23 -0700803 NALBitReader br(sei->data() + 1, sei->size() - 1);
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700804 // sei_message()
Chong Zhang862f8452014-06-26 19:55:23 -0700805 while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700806 uint32_t payload_type = 0;
807 size_t payload_size = 0;
808 uint8_t last_byte;
809
810 do {
811 last_byte = br.getBits(8);
812 payload_type += last_byte;
813 } while (last_byte == 0xFF);
814
815 do {
816 last_byte = br.getBits(8);
817 payload_size += last_byte;
818 } while (last_byte == 0xFF);
819
820 // sei_payload()
821 if (payload_type == 4) {
822 // user_data_registered_itu_t_t35()
823
824 // ATSC A/72: 6.4.2
825 uint8_t itu_t_t35_country_code = br.getBits(8);
826 uint16_t itu_t_t35_provider_code = br.getBits(16);
827 uint32_t user_identifier = br.getBits(32);
828 uint8_t user_data_type_code = br.getBits(8);
829
830 payload_size -= 1 + 2 + 4 + 1;
831
832 if (itu_t_t35_country_code == 0xB5
833 && itu_t_t35_provider_code == 0x0031
834 && user_identifier == 'GA94'
835 && user_data_type_code == 0x3) {
836 hasCC = true;
837
838 // MPEG_cc_data()
839 // ATSC A/53 Part 4: 6.2.3.1
840 br.skipBits(1); //process_em_data_flag
841 bool process_cc_data_flag = br.getBits(1);
842 br.skipBits(1); //additional_data_flag
843 size_t cc_count = br.getBits(5);
844 br.skipBits(8); // em_data;
845 payload_size -= 2;
846
847 if (process_cc_data_flag) {
848 AString out;
849
850 sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
851 ccBuf->setRange(0, 0);
852
853 for (size_t i = 0; i < cc_count; i++) {
854 uint8_t marker = br.getBits(5);
855 CHECK_EQ(marker, 0x1f);
856
857 bool cc_valid = br.getBits(1);
858 uint8_t cc_type = br.getBits(2);
859 // remove odd parity bit
860 uint8_t cc_data_1 = br.getBits(8) & 0x7f;
861 uint8_t cc_data_2 = br.getBits(8) & 0x7f;
862
863 if (cc_valid
864 && (cc_type == 0 || cc_type == 1)) {
865 CCData cc(cc_type, cc_data_1, cc_data_2);
866 if (!isNullPad(&cc)) {
867 memcpy(ccBuf->data() + ccBuf->size(),
868 (void *)&cc, sizeof(cc));
869 ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
870 }
871 }
872 }
873 payload_size -= cc_count * 3;
874
875 mCCMap.add(timeUs, ccBuf);
876 break;
877 }
878 } else {
879 ALOGV("Malformed SEI payload type 4");
880 }
881 } else {
882 ALOGV("Unsupported SEI payload type %d", payload_type);
883 }
884
885 // skipping remaining bits of this payload
886 br.skipBits(payload_size * 8);
887 }
888
889 return hasCC;
890}
891
892void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
893 if (extractFromSEI(accessUnit) && mTrackCount == 0) {
894 mTrackCount++;
895
896 ALOGI("Found CEA-608 track");
897 sp<AMessage> msg = mNotify->dup();
898 msg->setInt32("what", kWhatTrackAdded);
899 msg->post();
900 }
901 // TODO: extract CC from other sources
902}
903
904void NuPlayer::CCDecoder::display(int64_t timeUs) {
905 ssize_t index = mCCMap.indexOfKey(timeUs);
906 if (index < 0) {
907 ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
908 return;
909 }
910
911 sp<ABuffer> &ccBuf = mCCMap.editValueAt(index);
912
913 if (ccBuf->size() > 0) {
914#if 0
915 dumpBytePair(ccBuf);
916#endif
917
918 ccBuf->meta()->setInt32("trackIndex", mSelectedTrack);
919 ccBuf->meta()->setInt64("timeUs", timeUs);
920 ccBuf->meta()->setInt64("durationUs", 0ll);
921
922 sp<AMessage> msg = mNotify->dup();
923 msg->setInt32("what", kWhatClosedCaptionData);
924 msg->setBuffer("buffer", ccBuf);
925 msg->post();
926 }
927
928 // remove all entries before timeUs
929 mCCMap.removeItemsAt(0, index + 1);
930}
931
Andreas Huberf9334412010-12-15 15:17:42 -0800932} // namespace android
933