blob: 1b9bafbd73c7b12ccbb94ce975e9219253721cf1 [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());
158 mInputBufferIsDequeued.clear();
159 mInputBufferIsDequeued.resize(mInputBuffers.size());
160}
161
Lajos Molnar1cd13982014-01-17 15:12:51 -0800162void NuPlayer::Decoder::requestCodecNotification() {
163 if (mCodec != NULL) {
164 sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
165 reply->setInt32("generation", mBufferGeneration);
166 mCodec->requestActivityNotification(reply);
167 }
168}
169
170bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
171 int32_t generation;
172 CHECK(msg->findInt32("generation", &generation));
173 return generation != mBufferGeneration;
174}
175
176void NuPlayer::Decoder::init() {
177 mDecoderLooper->registerHandler(this);
178}
179
180void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
181 sp<AMessage> msg = new AMessage(kWhatConfigure, id());
182 msg->setMessage("format", format);
183 msg->post();
184}
185
Lajos Molnar09524832014-07-17 14:29:51 -0700186status_t NuPlayer::Decoder::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
187 sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id());
188 msg->setPointer("buffers", buffers);
189
190 sp<AMessage> response;
191 return PostAndAwaitResponse(msg, &response);
192}
193
Lajos Molnar1cd13982014-01-17 15:12:51 -0800194void NuPlayer::Decoder::handleError(int32_t err)
195{
196 sp<AMessage> notify = mNotify->dup();
197 notify->setInt32("what", kWhatError);
198 notify->setInt32("err", err);
199 notify->post();
200}
201
202bool NuPlayer::Decoder::handleAnInputBuffer() {
203 size_t bufferIx = -1;
204 status_t res = mCodec->dequeueInputBuffer(&bufferIx);
205 ALOGV("[%s] dequeued input: %d",
206 mComponentName.c_str(), res == OK ? (int)bufferIx : res);
207 if (res != OK) {
208 if (res != -EAGAIN) {
209 handleError(res);
210 }
211 return false;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700212 }
213
Lajos Molnar1cd13982014-01-17 15:12:51 -0800214 CHECK_LT(bufferIx, mInputBuffers.size());
Andreas Huberf9334412010-12-15 15:17:42 -0800215
Lajos Molnar09524832014-07-17 14:29:51 -0700216 if (mMediaBuffers[bufferIx] != NULL) {
217 mMediaBuffers[bufferIx]->release();
218 mMediaBuffers.editItemAt(bufferIx) = NULL;
219 }
220 mInputBufferIsDequeued.editItemAt(bufferIx) = true;
221
Lajos Molnar1cd13982014-01-17 15:12:51 -0800222 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
223 reply->setSize("buffer-ix", bufferIx);
224 reply->setInt32("generation", mBufferGeneration);
225
226 sp<AMessage> notify = mNotify->dup();
227 notify->setInt32("what", kWhatFillThisBuffer);
228 notify->setBuffer("buffer", mInputBuffers[bufferIx]);
229 notify->setMessage("reply", reply);
230 notify->post();
231 return true;
232}
233
234void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
235 size_t bufferIx;
236 CHECK(msg->findSize("buffer-ix", &bufferIx));
237 CHECK_LT(bufferIx, mInputBuffers.size());
238 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
239
240 sp<ABuffer> buffer;
241 bool hasBuffer = msg->findBuffer("buffer", &buffer);
Lajos Molnar09524832014-07-17 14:29:51 -0700242
243 // handle widevine classic source - that fills an arbitrary input buffer
244 MediaBuffer *mediaBuffer = NULL;
245 if (hasBuffer && buffer->meta()->findPointer(
246 "mediaBuffer", (void **)&mediaBuffer)) {
247 if (mediaBuffer == NULL) {
248 // received no actual buffer
249 ALOGW("[%s] received null MediaBuffer %s",
250 mComponentName.c_str(), msg->debugString().c_str());
251 buffer = NULL;
252 } else {
253 // likely filled another buffer than we requested: adjust buffer index
254 size_t ix;
255 for (ix = 0; ix < mInputBuffers.size(); ix++) {
256 const sp<ABuffer> &buf = mInputBuffers[ix];
257 if (buf->data() == mediaBuffer->data()) {
258 // all input buffers are dequeued on start, hence the check
259 CHECK(mInputBufferIsDequeued[ix]);
260 ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
261 mComponentName.c_str(), ix, bufferIx);
262
263 // TRICKY: need buffer for the metadata, so instead, set
264 // codecBuffer to the same (though incorrect) buffer to
265 // avoid a memcpy into the codecBuffer
266 codecBuffer = buffer;
267 codecBuffer->setRange(
268 mediaBuffer->range_offset(),
269 mediaBuffer->range_length());
270 bufferIx = ix;
271 break;
272 }
273 }
274 CHECK(ix < mInputBuffers.size());
275 }
276 }
277
278 mInputBufferIsDequeued.editItemAt(bufferIx) = false;
279
Lajos Molnar1cd13982014-01-17 15:12:51 -0800280 if (buffer == NULL /* includes !hasBuffer */) {
281 int32_t streamErr = ERROR_END_OF_STREAM;
282 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
283
284 if (streamErr == OK) {
285 /* buffers are returned to hold on to */
286 return;
287 }
288
289 // attempt to queue EOS
290 status_t err = mCodec->queueInputBuffer(
291 bufferIx,
292 0,
293 0,
294 0,
295 MediaCodec::BUFFER_FLAG_EOS);
296 if (streamErr == ERROR_END_OF_STREAM && err != OK) {
297 streamErr = err;
298 // err will not be ERROR_END_OF_STREAM
299 }
300
301 if (streamErr != ERROR_END_OF_STREAM) {
302 handleError(streamErr);
303 }
304 } else {
305 int64_t timeUs = 0;
306 uint32_t flags = 0;
307 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
308
309 int32_t eos;
310 // we do not expect CODECCONFIG or SYNCFRAME for decoder
311 if (buffer->meta()->findInt32("eos", &eos) && eos) {
312 flags |= MediaCodec::BUFFER_FLAG_EOS;
313 }
314
315 // copy into codec buffer
316 if (buffer != codecBuffer) {
317 CHECK_LE(buffer->size(), codecBuffer->capacity());
318 codecBuffer->setRange(0, buffer->size());
319 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
320 }
321
322 status_t err = mCodec->queueInputBuffer(
323 bufferIx,
324 codecBuffer->offset(),
325 codecBuffer->size(),
326 timeUs,
327 flags);
328 if (err != OK) {
329 ALOGE("Failed to queue input buffer for %s (err=%d)",
330 mComponentName.c_str(), err);
331 handleError(err);
332 }
Lajos Molnar09524832014-07-17 14:29:51 -0700333
334 if (mediaBuffer != NULL) {
335 CHECK(mMediaBuffers[bufferIx] == NULL);
336 mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
337 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800338 }
339}
340
341bool NuPlayer::Decoder::handleAnOutputBuffer() {
342 size_t bufferIx = -1;
343 size_t offset;
344 size_t size;
345 int64_t timeUs;
346 uint32_t flags;
347 status_t res = mCodec->dequeueOutputBuffer(
348 &bufferIx, &offset, &size, &timeUs, &flags);
349
350 if (res != OK) {
351 ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
352 } else {
353 ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
354 mComponentName.c_str(), (int)bufferIx, timeUs, flags);
355 }
356
357 if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
358 res = mCodec->getOutputBuffers(&mOutputBuffers);
359 if (res != OK) {
360 ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
361 mComponentName.c_str(), res);
362 handleError(res);
363 return false;
364 }
365 // NuPlayer ignores this
366 return true;
367 } else if (res == INFO_FORMAT_CHANGED) {
368 sp<AMessage> format = new AMessage();
369 res = mCodec->getOutputFormat(&format);
370 if (res != OK) {
371 ALOGE("Failed to get output format for %s after INFO event (err=%d)",
372 mComponentName.c_str(), res);
373 handleError(res);
374 return false;
375 }
376
377 sp<AMessage> notify = mNotify->dup();
378 notify->setInt32("what", kWhatOutputFormatChanged);
379 notify->setMessage("format", format);
380 notify->post();
381 return true;
382 } else if (res == INFO_DISCONTINUITY) {
383 // nothing to do
384 return true;
385 } else if (res != OK) {
386 if (res != -EAGAIN) {
387 handleError(res);
388 }
389 return false;
390 }
391
392 CHECK_LT(bufferIx, mOutputBuffers.size());
393 sp<ABuffer> buffer = mOutputBuffers[bufferIx];
394 buffer->setRange(offset, size);
395 buffer->meta()->clear();
396 buffer->meta()->setInt64("timeUs", timeUs);
397 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
398 buffer->meta()->setInt32("eos", true);
399 }
400 // we do not expect CODECCONFIG or SYNCFRAME for decoder
401
402 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
403 reply->setSize("buffer-ix", bufferIx);
404 reply->setInt32("generation", mBufferGeneration);
405
406 sp<AMessage> notify = mNotify->dup();
407 notify->setInt32("what", kWhatDrainThisBuffer);
408 notify->setBuffer("buffer", buffer);
409 notify->setMessage("reply", reply);
410 notify->post();
411
412 // FIXME: This should be handled after rendering is complete,
413 // but Renderer needs it now
414 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
415 ALOGV("queueing eos [%s]", mComponentName.c_str());
416 sp<AMessage> notify = mNotify->dup();
417 notify->setInt32("what", kWhatEOS);
418 notify->setInt32("err", ERROR_END_OF_STREAM);
419 notify->post();
420 }
421 return true;
422}
423
424void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
425 status_t err;
426 int32_t render;
427 size_t bufferIx;
428 CHECK(msg->findSize("buffer-ix", &bufferIx));
429 if (msg->findInt32("render", &render) && render) {
430 err = mCodec->renderOutputBufferAndRelease(bufferIx);
431 } else {
432 err = mCodec->releaseOutputBuffer(bufferIx);
433 }
434 if (err != OK) {
435 ALOGE("failed to release output buffer for %s (err=%d)",
436 mComponentName.c_str(), err);
437 handleError(err);
438 }
439}
440
441void NuPlayer::Decoder::onFlush() {
442 status_t err = OK;
443 if (mCodec != NULL) {
444 err = mCodec->flush();
445 ++mBufferGeneration;
446 }
447
448 if (err != OK) {
449 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
450 handleError(err);
451 return;
452 }
453
Lajos Molnar09524832014-07-17 14:29:51 -0700454 releaseAndResetMediaBuffers();
455
Lajos Molnar1cd13982014-01-17 15:12:51 -0800456 sp<AMessage> notify = mNotify->dup();
457 notify->setInt32("what", kWhatFlushCompleted);
458 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700459 mPaused = true;
460}
461
462void NuPlayer::Decoder::onResume() {
463 mPaused = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800464}
465
466void NuPlayer::Decoder::onShutdown() {
467 status_t err = OK;
468 if (mCodec != NULL) {
469 err = mCodec->release();
470 mCodec = NULL;
471 ++mBufferGeneration;
472
473 if (mNativeWindow != NULL) {
474 // reconnect to surface as MediaCodec disconnected from it
475 CHECK_EQ((int)NO_ERROR,
476 native_window_api_connect(
477 mNativeWindow->getNativeWindow().get(),
478 NATIVE_WINDOW_API_MEDIA));
479 }
480 mComponentName = "decoder";
481 }
482
Lajos Molnar09524832014-07-17 14:29:51 -0700483 releaseAndResetMediaBuffers();
484
Lajos Molnar1cd13982014-01-17 15:12:51 -0800485 if (err != OK) {
486 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
487 handleError(err);
488 return;
489 }
490
491 sp<AMessage> notify = mNotify->dup();
492 notify->setInt32("what", kWhatShutdownCompleted);
493 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700494 mPaused = true;
Andreas Huberf9334412010-12-15 15:17:42 -0800495}
496
497void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800498 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
499
Andreas Huberf9334412010-12-15 15:17:42 -0800500 switch (msg->what()) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800501 case kWhatConfigure:
502 {
503 sp<AMessage> format;
504 CHECK(msg->findMessage("format", &format));
505 onConfigure(format);
506 break;
507 }
508
Lajos Molnar09524832014-07-17 14:29:51 -0700509 case kWhatGetInputBuffers:
510 {
511 uint32_t replyID;
512 CHECK(msg->senderAwaitsResponse(&replyID));
513
514 Vector<sp<ABuffer> > *dstBuffers;
515 CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
516
517 dstBuffers->clear();
518 for (size_t i = 0; i < mInputBuffers.size(); i++) {
519 dstBuffers->push(mInputBuffers[i]);
520 }
521
522 (new AMessage)->postReply(replyID);
523 break;
524 }
525
Andreas Huberf9334412010-12-15 15:17:42 -0800526 case kWhatCodecNotify:
527 {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800528 if (!isStaleReply(msg)) {
Wei Jia704e7262014-06-04 16:21:56 -0700529 if (!mPaused) {
530 while (handleAnInputBuffer()) {
531 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800532 }
Andreas Huberf9334412010-12-15 15:17:42 -0800533
Lajos Molnar1cd13982014-01-17 15:12:51 -0800534 while (handleAnOutputBuffer()) {
535 }
Andreas Huberf9334412010-12-15 15:17:42 -0800536 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800537
538 requestCodecNotification();
539 break;
540 }
541
542 case kWhatInputBufferFilled:
543 {
544 if (!isStaleReply(msg)) {
545 onInputBufferFilled(msg);
546 }
547 break;
548 }
549
550 case kWhatRenderBuffer:
551 {
552 if (!isStaleReply(msg)) {
553 onRenderBuffer(msg);
554 }
555 break;
556 }
557
558 case kWhatFlush:
559 {
560 onFlush();
561 break;
562 }
563
Wei Jia704e7262014-06-04 16:21:56 -0700564 case kWhatResume:
565 {
566 onResume();
567 break;
568 }
569
Lajos Molnar1cd13982014-01-17 15:12:51 -0800570 case kWhatShutdown:
571 {
572 onShutdown();
Andreas Huberf9334412010-12-15 15:17:42 -0800573 break;
574 }
575
576 default:
577 TRESPASS();
578 break;
579 }
580}
581
Andreas Huberf9334412010-12-15 15:17:42 -0800582void NuPlayer::Decoder::signalFlush() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800583 (new AMessage(kWhatFlush, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800584}
585
586void NuPlayer::Decoder::signalResume() {
Wei Jia704e7262014-06-04 16:21:56 -0700587 (new AMessage(kWhatResume, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800588}
589
Andreas Huber3831a062010-12-21 10:22:33 -0800590void NuPlayer::Decoder::initiateShutdown() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800591 (new AMessage(kWhatShutdown, id()))->post();
Andreas Huber3831a062010-12-21 10:22:33 -0800592}
593
Robert Shih6d0a94e2014-01-23 16:18:22 -0800594bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
595 if (targetFormat == NULL) {
596 return true;
597 }
598
599 AString mime;
600 if (!targetFormat->findString("mime", &mime)) {
601 return false;
602 }
603
604 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
605 // field-by-field comparison
606 const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
607 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
608 int32_t oldVal, newVal;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800609 if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
610 !targetFormat->findInt32(keys[i], &newVal) ||
611 oldVal != newVal) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800612 return false;
613 }
614 }
615
616 sp<ABuffer> oldBuf, newBuf;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800617 if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
618 targetFormat->findBuffer("csd-0", &newBuf)) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800619 if (oldBuf->size() != newBuf->size()) {
620 return false;
621 }
622 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
623 }
624 }
625 return false;
626}
627
628bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800629 if (mOutputFormat == NULL) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800630 return false;
631 }
632
633 if (targetFormat == NULL) {
634 return true;
635 }
636
637 AString oldMime, newMime;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800638 if (!mOutputFormat->findString("mime", &oldMime)
Robert Shih6d0a94e2014-01-23 16:18:22 -0800639 || !targetFormat->findString("mime", &newMime)
640 || !(oldMime == newMime)) {
641 return false;
642 }
643
644 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
645 bool seamless;
646 if (audio) {
647 seamless = supportsSeamlessAudioFormatChange(targetFormat);
648 } else {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800649 int32_t isAdaptive;
650 seamless = (mCodec != NULL &&
651 mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
652 isAdaptive);
Robert Shih6d0a94e2014-01-23 16:18:22 -0800653 }
654
655 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
656 return seamless;
657}
658
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700659struct NuPlayer::CCDecoder::CCData {
660 CCData(uint8_t type, uint8_t data1, uint8_t data2)
661 : mType(type), mData1(data1), mData2(data2) {
662 }
663
664 uint8_t mType;
665 uint8_t mData1;
666 uint8_t mData2;
667};
668
669NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
670 : mNotify(notify),
671 mTrackCount(0),
672 mSelectedTrack(-1) {
673}
674
675size_t NuPlayer::CCDecoder::getTrackCount() const {
676 return mTrackCount;
677}
678
679sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
680 CHECK(index == 0);
681
682 sp<AMessage> format = new AMessage();
683
684 format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
685 format->setString("language", "und");
686 format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
687 format->setInt32("auto", 1);
688 format->setInt32("default", 1);
689 format->setInt32("forced", 0);
690
691 return format;
692}
693
694status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
695 CHECK(index < mTrackCount);
696
697 if (select) {
698 if (mSelectedTrack == (ssize_t)index) {
699 ALOGE("track %zu already selected", index);
700 return BAD_VALUE;
701 }
702 ALOGV("selected track %zu", index);
703 mSelectedTrack = index;
704 } else {
705 if (mSelectedTrack != (ssize_t)index) {
706 ALOGE("track %zu is not selected", index);
707 return BAD_VALUE;
708 }
709 ALOGV("unselected track %zu", index);
710 mSelectedTrack = -1;
711 }
712
713 return OK;
714}
715
716bool NuPlayer::CCDecoder::isSelected() const {
717 return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount;
718}
719
720bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const {
721 return cc->mData1 < 0x10 && cc->mData2 < 0x10;
722}
723
724void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const {
725 size_t offset = 0;
726 AString out;
727
728 while (offset < ccBuf->size()) {
729 char tmp[128];
730
731 CCData *cc = (CCData *) (ccBuf->data() + offset);
732
733 if (isNullPad(cc)) {
734 // 1 null pad or XDS metadata, ignore
735 offset += sizeof(CCData);
736 continue;
737 }
738
739 if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
740 // 2 basic chars
741 sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
742 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
743 && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
744 // 1 special char
745 sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
746 } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
747 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
748 // 1 Spanish/French char
749 sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
750 } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
751 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
752 // 1 Portuguese/German/Danish char
753 sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
754 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
755 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
756 // Mid-Row Codes (Table 69)
757 sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
758 } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
759 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
760 ||
761 ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
762 && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
763 // Misc Control Codes (Table 70)
764 sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
765 } else if ((cc->mData1 & 0x70) == 0x10
766 && (cc->mData2 & 0x40) == 0x40
767 && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
768 // Preamble Address Codes (Table 71)
769 sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
770 } else {
771 sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
772 }
773
774 if (out.size() > 0) {
775 out.append(", ");
776 }
777
778 out.append(tmp);
779
780 offset += sizeof(CCData);
781 }
782
783 ALOGI("%s", out.c_str());
784}
785
786bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
787 int64_t timeUs;
788 CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
789
790 sp<ABuffer> sei;
791 if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
792 return false;
793 }
794
795 bool hasCC = false;
796
Chong Zhang862f8452014-06-26 19:55:23 -0700797 NALBitReader br(sei->data() + 1, sei->size() - 1);
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700798 // sei_message()
Chong Zhang862f8452014-06-26 19:55:23 -0700799 while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700800 uint32_t payload_type = 0;
801 size_t payload_size = 0;
802 uint8_t last_byte;
803
804 do {
805 last_byte = br.getBits(8);
806 payload_type += last_byte;
807 } while (last_byte == 0xFF);
808
809 do {
810 last_byte = br.getBits(8);
811 payload_size += last_byte;
812 } while (last_byte == 0xFF);
813
814 // sei_payload()
815 if (payload_type == 4) {
816 // user_data_registered_itu_t_t35()
817
818 // ATSC A/72: 6.4.2
819 uint8_t itu_t_t35_country_code = br.getBits(8);
820 uint16_t itu_t_t35_provider_code = br.getBits(16);
821 uint32_t user_identifier = br.getBits(32);
822 uint8_t user_data_type_code = br.getBits(8);
823
824 payload_size -= 1 + 2 + 4 + 1;
825
826 if (itu_t_t35_country_code == 0xB5
827 && itu_t_t35_provider_code == 0x0031
828 && user_identifier == 'GA94'
829 && user_data_type_code == 0x3) {
830 hasCC = true;
831
832 // MPEG_cc_data()
833 // ATSC A/53 Part 4: 6.2.3.1
834 br.skipBits(1); //process_em_data_flag
835 bool process_cc_data_flag = br.getBits(1);
836 br.skipBits(1); //additional_data_flag
837 size_t cc_count = br.getBits(5);
838 br.skipBits(8); // em_data;
839 payload_size -= 2;
840
841 if (process_cc_data_flag) {
842 AString out;
843
844 sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
845 ccBuf->setRange(0, 0);
846
847 for (size_t i = 0; i < cc_count; i++) {
848 uint8_t marker = br.getBits(5);
849 CHECK_EQ(marker, 0x1f);
850
851 bool cc_valid = br.getBits(1);
852 uint8_t cc_type = br.getBits(2);
853 // remove odd parity bit
854 uint8_t cc_data_1 = br.getBits(8) & 0x7f;
855 uint8_t cc_data_2 = br.getBits(8) & 0x7f;
856
857 if (cc_valid
858 && (cc_type == 0 || cc_type == 1)) {
859 CCData cc(cc_type, cc_data_1, cc_data_2);
860 if (!isNullPad(&cc)) {
861 memcpy(ccBuf->data() + ccBuf->size(),
862 (void *)&cc, sizeof(cc));
863 ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
864 }
865 }
866 }
867 payload_size -= cc_count * 3;
868
869 mCCMap.add(timeUs, ccBuf);
870 break;
871 }
872 } else {
873 ALOGV("Malformed SEI payload type 4");
874 }
875 } else {
876 ALOGV("Unsupported SEI payload type %d", payload_type);
877 }
878
879 // skipping remaining bits of this payload
880 br.skipBits(payload_size * 8);
881 }
882
883 return hasCC;
884}
885
886void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
887 if (extractFromSEI(accessUnit) && mTrackCount == 0) {
888 mTrackCount++;
889
890 ALOGI("Found CEA-608 track");
891 sp<AMessage> msg = mNotify->dup();
892 msg->setInt32("what", kWhatTrackAdded);
893 msg->post();
894 }
895 // TODO: extract CC from other sources
896}
897
898void NuPlayer::CCDecoder::display(int64_t timeUs) {
899 ssize_t index = mCCMap.indexOfKey(timeUs);
900 if (index < 0) {
901 ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
902 return;
903 }
904
905 sp<ABuffer> &ccBuf = mCCMap.editValueAt(index);
906
907 if (ccBuf->size() > 0) {
908#if 0
909 dumpBytePair(ccBuf);
910#endif
911
912 ccBuf->meta()->setInt32("trackIndex", mSelectedTrack);
913 ccBuf->meta()->setInt64("timeUs", timeUs);
914 ccBuf->meta()->setInt64("durationUs", 0ll);
915
916 sp<AMessage> msg = mNotify->dup();
917 msg->setInt32("what", kWhatClosedCaptionData);
918 msg->setBuffer("buffer", ccBuf);
919 msg->post();
920 }
921
922 // remove all entries before timeUs
923 mCCMap.removeItemsAt(0, index + 1);
924}
925
Andreas Huberf9334412010-12-15 15:17:42 -0800926} // namespace android
927