blob: 37ecbf1328083aca53162f08386375f1cdd7e8fe [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
Wei Jia3fb9f682014-08-20 14:30:09 -0700481 status_t error =
Lajos Molnar1cd13982014-01-17 15:12:51 -0800482 native_window_api_connect(
483 mNativeWindow->getNativeWindow().get(),
Wei Jia3fb9f682014-08-20 14:30:09 -0700484 NATIVE_WINDOW_API_MEDIA);
485 ALOGW_IF(error != NO_ERROR,
486 "[%s] failed to connect to native window, error=%d",
487 mComponentName.c_str(), error);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800488 }
489 mComponentName = "decoder";
490 }
491
Lajos Molnar09524832014-07-17 14:29:51 -0700492 releaseAndResetMediaBuffers();
493
Lajos Molnar1cd13982014-01-17 15:12:51 -0800494 if (err != OK) {
495 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
496 handleError(err);
497 return;
498 }
499
500 sp<AMessage> notify = mNotify->dup();
501 notify->setInt32("what", kWhatShutdownCompleted);
502 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700503 mPaused = true;
Andreas Huberf9334412010-12-15 15:17:42 -0800504}
505
506void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800507 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
508
Andreas Huberf9334412010-12-15 15:17:42 -0800509 switch (msg->what()) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800510 case kWhatConfigure:
511 {
512 sp<AMessage> format;
513 CHECK(msg->findMessage("format", &format));
514 onConfigure(format);
515 break;
516 }
517
Lajos Molnar09524832014-07-17 14:29:51 -0700518 case kWhatGetInputBuffers:
519 {
520 uint32_t replyID;
521 CHECK(msg->senderAwaitsResponse(&replyID));
522
523 Vector<sp<ABuffer> > *dstBuffers;
524 CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
525
526 dstBuffers->clear();
527 for (size_t i = 0; i < mInputBuffers.size(); i++) {
528 dstBuffers->push(mInputBuffers[i]);
529 }
530
531 (new AMessage)->postReply(replyID);
532 break;
533 }
534
Andreas Huberf9334412010-12-15 15:17:42 -0800535 case kWhatCodecNotify:
536 {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800537 if (!isStaleReply(msg)) {
Wei Jia704e7262014-06-04 16:21:56 -0700538 if (!mPaused) {
539 while (handleAnInputBuffer()) {
540 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800541 }
Andreas Huberf9334412010-12-15 15:17:42 -0800542
Lajos Molnar1cd13982014-01-17 15:12:51 -0800543 while (handleAnOutputBuffer()) {
544 }
Andreas Huberf9334412010-12-15 15:17:42 -0800545 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800546
547 requestCodecNotification();
548 break;
549 }
550
551 case kWhatInputBufferFilled:
552 {
553 if (!isStaleReply(msg)) {
554 onInputBufferFilled(msg);
555 }
556 break;
557 }
558
559 case kWhatRenderBuffer:
560 {
561 if (!isStaleReply(msg)) {
562 onRenderBuffer(msg);
563 }
564 break;
565 }
566
567 case kWhatFlush:
568 {
569 onFlush();
570 break;
571 }
572
Wei Jia704e7262014-06-04 16:21:56 -0700573 case kWhatResume:
574 {
575 onResume();
576 break;
577 }
578
Lajos Molnar1cd13982014-01-17 15:12:51 -0800579 case kWhatShutdown:
580 {
581 onShutdown();
Andreas Huberf9334412010-12-15 15:17:42 -0800582 break;
583 }
584
585 default:
586 TRESPASS();
587 break;
588 }
589}
590
Andreas Huberf9334412010-12-15 15:17:42 -0800591void NuPlayer::Decoder::signalFlush() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800592 (new AMessage(kWhatFlush, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800593}
594
595void NuPlayer::Decoder::signalResume() {
Wei Jia704e7262014-06-04 16:21:56 -0700596 (new AMessage(kWhatResume, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800597}
598
Andreas Huber3831a062010-12-21 10:22:33 -0800599void NuPlayer::Decoder::initiateShutdown() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800600 (new AMessage(kWhatShutdown, id()))->post();
Andreas Huber3831a062010-12-21 10:22:33 -0800601}
602
Robert Shih6d0a94e2014-01-23 16:18:22 -0800603bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
604 if (targetFormat == NULL) {
605 return true;
606 }
607
608 AString mime;
609 if (!targetFormat->findString("mime", &mime)) {
610 return false;
611 }
612
613 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
614 // field-by-field comparison
615 const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
616 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
617 int32_t oldVal, newVal;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800618 if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
619 !targetFormat->findInt32(keys[i], &newVal) ||
620 oldVal != newVal) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800621 return false;
622 }
623 }
624
625 sp<ABuffer> oldBuf, newBuf;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800626 if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
627 targetFormat->findBuffer("csd-0", &newBuf)) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800628 if (oldBuf->size() != newBuf->size()) {
629 return false;
630 }
631 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
632 }
633 }
634 return false;
635}
636
637bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800638 if (mOutputFormat == NULL) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800639 return false;
640 }
641
642 if (targetFormat == NULL) {
643 return true;
644 }
645
646 AString oldMime, newMime;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800647 if (!mOutputFormat->findString("mime", &oldMime)
Robert Shih6d0a94e2014-01-23 16:18:22 -0800648 || !targetFormat->findString("mime", &newMime)
649 || !(oldMime == newMime)) {
650 return false;
651 }
652
653 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
654 bool seamless;
655 if (audio) {
656 seamless = supportsSeamlessAudioFormatChange(targetFormat);
657 } else {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800658 int32_t isAdaptive;
659 seamless = (mCodec != NULL &&
660 mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
661 isAdaptive);
Robert Shih6d0a94e2014-01-23 16:18:22 -0800662 }
663
664 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
665 return seamless;
666}
667
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700668struct NuPlayer::CCDecoder::CCData {
669 CCData(uint8_t type, uint8_t data1, uint8_t data2)
670 : mType(type), mData1(data1), mData2(data2) {
671 }
672
673 uint8_t mType;
674 uint8_t mData1;
675 uint8_t mData2;
676};
677
678NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
679 : mNotify(notify),
680 mTrackCount(0),
681 mSelectedTrack(-1) {
682}
683
684size_t NuPlayer::CCDecoder::getTrackCount() const {
685 return mTrackCount;
686}
687
688sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
689 CHECK(index == 0);
690
691 sp<AMessage> format = new AMessage();
692
693 format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
694 format->setString("language", "und");
695 format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
696 format->setInt32("auto", 1);
697 format->setInt32("default", 1);
698 format->setInt32("forced", 0);
699
700 return format;
701}
702
703status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
704 CHECK(index < mTrackCount);
705
706 if (select) {
707 if (mSelectedTrack == (ssize_t)index) {
708 ALOGE("track %zu already selected", index);
709 return BAD_VALUE;
710 }
711 ALOGV("selected track %zu", index);
712 mSelectedTrack = index;
713 } else {
714 if (mSelectedTrack != (ssize_t)index) {
715 ALOGE("track %zu is not selected", index);
716 return BAD_VALUE;
717 }
718 ALOGV("unselected track %zu", index);
719 mSelectedTrack = -1;
720 }
721
722 return OK;
723}
724
725bool NuPlayer::CCDecoder::isSelected() const {
726 return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount;
727}
728
729bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const {
730 return cc->mData1 < 0x10 && cc->mData2 < 0x10;
731}
732
733void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const {
734 size_t offset = 0;
735 AString out;
736
737 while (offset < ccBuf->size()) {
738 char tmp[128];
739
740 CCData *cc = (CCData *) (ccBuf->data() + offset);
741
742 if (isNullPad(cc)) {
743 // 1 null pad or XDS metadata, ignore
744 offset += sizeof(CCData);
745 continue;
746 }
747
748 if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
749 // 2 basic chars
750 sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
751 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
752 && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
753 // 1 special char
754 sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
755 } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
756 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
757 // 1 Spanish/French char
758 sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
759 } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
760 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
761 // 1 Portuguese/German/Danish char
762 sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
763 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
764 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
765 // Mid-Row Codes (Table 69)
766 sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
767 } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
768 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
769 ||
770 ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
771 && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
772 // Misc Control Codes (Table 70)
773 sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
774 } else if ((cc->mData1 & 0x70) == 0x10
775 && (cc->mData2 & 0x40) == 0x40
776 && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
777 // Preamble Address Codes (Table 71)
778 sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
779 } else {
780 sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
781 }
782
783 if (out.size() > 0) {
784 out.append(", ");
785 }
786
787 out.append(tmp);
788
789 offset += sizeof(CCData);
790 }
791
792 ALOGI("%s", out.c_str());
793}
794
795bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
796 int64_t timeUs;
797 CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
798
799 sp<ABuffer> sei;
800 if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
801 return false;
802 }
803
804 bool hasCC = false;
805
Chong Zhang862f8452014-06-26 19:55:23 -0700806 NALBitReader br(sei->data() + 1, sei->size() - 1);
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700807 // sei_message()
Chong Zhang862f8452014-06-26 19:55:23 -0700808 while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700809 uint32_t payload_type = 0;
810 size_t payload_size = 0;
811 uint8_t last_byte;
812
813 do {
814 last_byte = br.getBits(8);
815 payload_type += last_byte;
816 } while (last_byte == 0xFF);
817
818 do {
819 last_byte = br.getBits(8);
820 payload_size += last_byte;
821 } while (last_byte == 0xFF);
822
823 // sei_payload()
824 if (payload_type == 4) {
825 // user_data_registered_itu_t_t35()
826
827 // ATSC A/72: 6.4.2
828 uint8_t itu_t_t35_country_code = br.getBits(8);
829 uint16_t itu_t_t35_provider_code = br.getBits(16);
830 uint32_t user_identifier = br.getBits(32);
831 uint8_t user_data_type_code = br.getBits(8);
832
833 payload_size -= 1 + 2 + 4 + 1;
834
835 if (itu_t_t35_country_code == 0xB5
836 && itu_t_t35_provider_code == 0x0031
837 && user_identifier == 'GA94'
838 && user_data_type_code == 0x3) {
839 hasCC = true;
840
841 // MPEG_cc_data()
842 // ATSC A/53 Part 4: 6.2.3.1
843 br.skipBits(1); //process_em_data_flag
844 bool process_cc_data_flag = br.getBits(1);
845 br.skipBits(1); //additional_data_flag
846 size_t cc_count = br.getBits(5);
847 br.skipBits(8); // em_data;
848 payload_size -= 2;
849
850 if (process_cc_data_flag) {
851 AString out;
852
853 sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
854 ccBuf->setRange(0, 0);
855
856 for (size_t i = 0; i < cc_count; i++) {
857 uint8_t marker = br.getBits(5);
858 CHECK_EQ(marker, 0x1f);
859
860 bool cc_valid = br.getBits(1);
861 uint8_t cc_type = br.getBits(2);
862 // remove odd parity bit
863 uint8_t cc_data_1 = br.getBits(8) & 0x7f;
864 uint8_t cc_data_2 = br.getBits(8) & 0x7f;
865
866 if (cc_valid
867 && (cc_type == 0 || cc_type == 1)) {
868 CCData cc(cc_type, cc_data_1, cc_data_2);
869 if (!isNullPad(&cc)) {
870 memcpy(ccBuf->data() + ccBuf->size(),
871 (void *)&cc, sizeof(cc));
872 ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
873 }
874 }
875 }
876 payload_size -= cc_count * 3;
877
878 mCCMap.add(timeUs, ccBuf);
879 break;
880 }
881 } else {
882 ALOGV("Malformed SEI payload type 4");
883 }
884 } else {
885 ALOGV("Unsupported SEI payload type %d", payload_type);
886 }
887
888 // skipping remaining bits of this payload
889 br.skipBits(payload_size * 8);
890 }
891
892 return hasCC;
893}
894
895void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
896 if (extractFromSEI(accessUnit) && mTrackCount == 0) {
897 mTrackCount++;
898
899 ALOGI("Found CEA-608 track");
900 sp<AMessage> msg = mNotify->dup();
901 msg->setInt32("what", kWhatTrackAdded);
902 msg->post();
903 }
904 // TODO: extract CC from other sources
905}
906
907void NuPlayer::CCDecoder::display(int64_t timeUs) {
908 ssize_t index = mCCMap.indexOfKey(timeUs);
909 if (index < 0) {
910 ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
911 return;
912 }
913
914 sp<ABuffer> &ccBuf = mCCMap.editValueAt(index);
915
916 if (ccBuf->size() > 0) {
917#if 0
918 dumpBytePair(ccBuf);
919#endif
920
921 ccBuf->meta()->setInt32("trackIndex", mSelectedTrack);
922 ccBuf->meta()->setInt64("timeUs", timeUs);
923 ccBuf->meta()->setInt64("durationUs", 0ll);
924
925 sp<AMessage> msg = mNotify->dup();
926 msg->setInt32("what", kWhatClosedCaptionData);
927 msg->setBuffer("buffer", ccBuf);
928 msg->post();
929 }
930
931 // remove all entries before timeUs
932 mCCMap.removeItemsAt(0, index + 1);
933}
934
Andreas Huberf9334412010-12-15 15:17:42 -0800935} // namespace android
936