blob: 037b5d277cb5cd0bfddd887e120855fadf8974e9 [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;
Marco Nelissen9e2b7912014-08-18 16:13:03 -070047 mDecoderLooper->setName("NPDecoder");
Lajos Molnar1cd13982014-01-17 15:12:51 -080048 mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
49
50 mCodecLooper = new ALooper;
Marco Nelissen9e2b7912014-08-18 16:13:03 -070051 mCodecLooper->setName("NPDecoder-CL");
Lajos Molnar1cd13982014-01-17 15:12:51 -080052 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
Andreas Huberf9334412010-12-15 15:17:42 -080053}
54
55NuPlayer::Decoder::~Decoder() {
Wei Jia4923cee2014-09-24 14:25:19 -070056 mDecoderLooper->unregisterHandler(id());
57 mDecoderLooper->stop();
58
59 releaseAndResetMediaBuffers();
Andreas Huberf9334412010-12-15 15:17:42 -080060}
61
Lajos Molnar09524832014-07-17 14:29:51 -070062static
63status_t PostAndAwaitResponse(
64 const sp<AMessage> &msg, sp<AMessage> *response) {
65 status_t err = msg->postAndAwaitResponse(response);
66
67 if (err != OK) {
68 return err;
69 }
70
71 if (!(*response)->findInt32("err", &err)) {
72 err = OK;
73 }
74
75 return err;
76}
77
Lajos Molnar87603c02014-08-20 19:25:30 -070078void NuPlayer::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) {
79 mCSDsForCurrentFormat.clear();
80 for (int32_t i = 0; ; ++i) {
81 AString tag = "csd-";
82 tag.append(i);
83 sp<ABuffer> buffer;
84 if (!format->findBuffer(tag.c_str(), &buffer)) {
85 break;
86 }
87 mCSDsForCurrentFormat.push(buffer);
88 }
89}
90
Lajos Molnar1cd13982014-01-17 15:12:51 -080091void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
Andreas Huberf9334412010-12-15 15:17:42 -080092 CHECK(mCodec == NULL);
Andreas Huberf9334412010-12-15 15:17:42 -080093
Lajos Molnar1cd13982014-01-17 15:12:51 -080094 ++mBufferGeneration;
95
Andreas Huber84066782011-08-16 09:34:26 -070096 AString mime;
97 CHECK(format->findString("mime", &mime));
Andreas Huberf9334412010-12-15 15:17:42 -080098
Lajos Molnar1cd13982014-01-17 15:12:51 -080099 sp<Surface> surface = NULL;
100 if (mNativeWindow != NULL) {
101 surface = mNativeWindow->getSurfaceTextureClient();
Andreas Huber84066782011-08-16 09:34:26 -0700102 }
Andreas Huberf9334412010-12-15 15:17:42 -0800103
Lajos Molnar1cd13982014-01-17 15:12:51 -0800104 mComponentName = mime;
105 mComponentName.append(" decoder");
106 ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
107
108 mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
Lajos Molnar09524832014-07-17 14:29:51 -0700109 int32_t secure = 0;
110 if (format->findInt32("secure", &secure) && secure != 0) {
111 if (mCodec != NULL) {
112 mCodec->getName(&mComponentName);
113 mComponentName.append(".secure");
114 mCodec->release();
115 ALOGI("[%s] creating", mComponentName.c_str());
116 mCodec = MediaCodec::CreateByComponentName(
117 mCodecLooper, mComponentName.c_str());
118 }
119 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800120 if (mCodec == NULL) {
Lajos Molnar09524832014-07-17 14:29:51 -0700121 ALOGE("Failed to create %s%s decoder",
122 (secure ? "secure " : ""), mime.c_str());
Lajos Molnar1cd13982014-01-17 15:12:51 -0800123 handleError(UNKNOWN_ERROR);
124 return;
125 }
126
127 mCodec->getName(&mComponentName);
128
Lajos Molnar14986f62014-09-15 11:04:44 -0700129 status_t err;
Glenn Kasten11731182011-02-08 17:26:17 -0800130 if (mNativeWindow != NULL) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800131 // disconnect from surface as MediaCodec will reconnect
Lajos Molnar14986f62014-09-15 11:04:44 -0700132 err = native_window_api_disconnect(
133 surface.get(), NATIVE_WINDOW_API_MEDIA);
134 // We treat this as a warning, as this is a preparatory step.
135 // Codec will try to connect to the surface, which is where
136 // any error signaling will occur.
137 ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800138 }
Lajos Molnar14986f62014-09-15 11:04:44 -0700139 err = mCodec->configure(
Lajos Molnar1cd13982014-01-17 15:12:51 -0800140 format, surface, NULL /* crypto */, 0 /* flags */);
141 if (err != OK) {
142 ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
143 handleError(err);
144 return;
145 }
Lajos Molnar87603c02014-08-20 19:25:30 -0700146 rememberCodecSpecificData(format);
147
Lajos Molnar1cd13982014-01-17 15:12:51 -0800148 // the following should work in configured state
149 CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
150 CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
151
152 err = mCodec->start();
153 if (err != OK) {
154 ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
155 handleError(err);
156 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800157 }
158
Lajos Molnar1cd13982014-01-17 15:12:51 -0800159 // the following should work after start
160 CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
Lajos Molnar09524832014-07-17 14:29:51 -0700161 releaseAndResetMediaBuffers();
Lajos Molnar1cd13982014-01-17 15:12:51 -0800162 CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
163 ALOGV("[%s] got %zu input and %zu output buffers",
164 mComponentName.c_str(),
165 mInputBuffers.size(),
166 mOutputBuffers.size());
Andreas Huber078cfcf2011-09-15 12:25:04 -0700167
Lajos Molnar1cd13982014-01-17 15:12:51 -0800168 requestCodecNotification();
Wei Jia704e7262014-06-04 16:21:56 -0700169 mPaused = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800170}
Andreas Huber078cfcf2011-09-15 12:25:04 -0700171
Lajos Molnar09524832014-07-17 14:29:51 -0700172void NuPlayer::Decoder::releaseAndResetMediaBuffers() {
173 for (size_t i = 0; i < mMediaBuffers.size(); i++) {
174 if (mMediaBuffers[i] != NULL) {
175 mMediaBuffers[i]->release();
176 mMediaBuffers.editItemAt(i) = NULL;
177 }
178 }
179 mMediaBuffers.resize(mInputBuffers.size());
Wei Jia81e50d02014-07-24 10:28:47 -0700180 for (size_t i = 0; i < mMediaBuffers.size(); i++) {
181 mMediaBuffers.editItemAt(i) = NULL;
182 }
Lajos Molnar09524832014-07-17 14:29:51 -0700183 mInputBufferIsDequeued.clear();
184 mInputBufferIsDequeued.resize(mInputBuffers.size());
Wei Jia81e50d02014-07-24 10:28:47 -0700185 for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
186 mInputBufferIsDequeued.editItemAt(i) = false;
187 }
Wei Jia2245fc62014-10-02 15:12:25 -0700188
189 mPendingInputMessages.clear();
Lajos Molnar09524832014-07-17 14:29:51 -0700190}
191
Lajos Molnar1cd13982014-01-17 15:12:51 -0800192void NuPlayer::Decoder::requestCodecNotification() {
193 if (mCodec != NULL) {
194 sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
195 reply->setInt32("generation", mBufferGeneration);
196 mCodec->requestActivityNotification(reply);
197 }
198}
199
200bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
201 int32_t generation;
202 CHECK(msg->findInt32("generation", &generation));
203 return generation != mBufferGeneration;
204}
205
206void NuPlayer::Decoder::init() {
207 mDecoderLooper->registerHandler(this);
208}
209
210void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
211 sp<AMessage> msg = new AMessage(kWhatConfigure, id());
212 msg->setMessage("format", format);
213 msg->post();
214}
215
Lajos Molnar87603c02014-08-20 19:25:30 -0700216void NuPlayer::Decoder::signalUpdateFormat(const sp<AMessage> &format) {
217 sp<AMessage> msg = new AMessage(kWhatUpdateFormat, id());
218 msg->setMessage("format", format);
219 msg->post();
220}
221
Lajos Molnar09524832014-07-17 14:29:51 -0700222status_t NuPlayer::Decoder::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
223 sp<AMessage> msg = new AMessage(kWhatGetInputBuffers, id());
224 msg->setPointer("buffers", buffers);
225
226 sp<AMessage> response;
227 return PostAndAwaitResponse(msg, &response);
228}
229
Lajos Molnar1cd13982014-01-17 15:12:51 -0800230void NuPlayer::Decoder::handleError(int32_t err)
231{
Andy Hungcf31f1e2014-09-23 14:59:01 -0700232 // We cannot immediately release the codec due to buffers still outstanding
233 // in the renderer. We signal to the player the error so it can shutdown/release the
234 // decoder after flushing and increment the generation to discard unnecessary messages.
235
236 ++mBufferGeneration;
Wei Jiac22c6952014-08-29 14:47:50 -0700237
Lajos Molnar1cd13982014-01-17 15:12:51 -0800238 sp<AMessage> notify = mNotify->dup();
239 notify->setInt32("what", kWhatError);
240 notify->setInt32("err", err);
241 notify->post();
242}
243
244bool NuPlayer::Decoder::handleAnInputBuffer() {
245 size_t bufferIx = -1;
246 status_t res = mCodec->dequeueInputBuffer(&bufferIx);
247 ALOGV("[%s] dequeued input: %d",
248 mComponentName.c_str(), res == OK ? (int)bufferIx : res);
249 if (res != OK) {
250 if (res != -EAGAIN) {
Andy Hungcf31f1e2014-09-23 14:59:01 -0700251 ALOGE("Failed to dequeue input buffer for %s (err=%d)",
252 mComponentName.c_str(), res);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800253 handleError(res);
254 }
255 return false;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700256 }
257
Lajos Molnar1cd13982014-01-17 15:12:51 -0800258 CHECK_LT(bufferIx, mInputBuffers.size());
Andreas Huberf9334412010-12-15 15:17:42 -0800259
Lajos Molnar09524832014-07-17 14:29:51 -0700260 if (mMediaBuffers[bufferIx] != NULL) {
261 mMediaBuffers[bufferIx]->release();
262 mMediaBuffers.editItemAt(bufferIx) = NULL;
263 }
264 mInputBufferIsDequeued.editItemAt(bufferIx) = true;
265
Lajos Molnar1cd13982014-01-17 15:12:51 -0800266 sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
267 reply->setSize("buffer-ix", bufferIx);
268 reply->setInt32("generation", mBufferGeneration);
269
Lajos Molnar87603c02014-08-20 19:25:30 -0700270 if (!mCSDsToSubmit.isEmpty()) {
271 sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
272 ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
273 reply->setBuffer("buffer", buffer);
274 mCSDsToSubmit.removeAt(0);
Wei Jia2245fc62014-10-02 15:12:25 -0700275 CHECK(onInputBufferFilled(reply));
276 return true;
277 }
278
279 while (!mPendingInputMessages.empty()) {
280 sp<AMessage> msg = *mPendingInputMessages.begin();
281 if (!onInputBufferFilled(msg)) {
282 break;
283 }
284 mPendingInputMessages.erase(mPendingInputMessages.begin());
285 }
286
287 if (!mInputBufferIsDequeued.editItemAt(bufferIx)) {
Lajos Molnar87603c02014-08-20 19:25:30 -0700288 return true;
289 }
290
Lajos Molnar1cd13982014-01-17 15:12:51 -0800291 sp<AMessage> notify = mNotify->dup();
292 notify->setInt32("what", kWhatFillThisBuffer);
293 notify->setBuffer("buffer", mInputBuffers[bufferIx]);
294 notify->setMessage("reply", reply);
295 notify->post();
296 return true;
297}
298
Wei Jia2245fc62014-10-02 15:12:25 -0700299bool android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800300 size_t bufferIx;
301 CHECK(msg->findSize("buffer-ix", &bufferIx));
302 CHECK_LT(bufferIx, mInputBuffers.size());
303 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
304
305 sp<ABuffer> buffer;
306 bool hasBuffer = msg->findBuffer("buffer", &buffer);
Lajos Molnar09524832014-07-17 14:29:51 -0700307
308 // handle widevine classic source - that fills an arbitrary input buffer
309 MediaBuffer *mediaBuffer = NULL;
Wei Jia96e92b52014-09-18 17:36:20 -0700310 if (hasBuffer) {
311 mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase());
312 if (mediaBuffer != NULL) {
Lajos Molnar09524832014-07-17 14:29:51 -0700313 // likely filled another buffer than we requested: adjust buffer index
314 size_t ix;
315 for (ix = 0; ix < mInputBuffers.size(); ix++) {
316 const sp<ABuffer> &buf = mInputBuffers[ix];
317 if (buf->data() == mediaBuffer->data()) {
318 // all input buffers are dequeued on start, hence the check
Wei Jia2245fc62014-10-02 15:12:25 -0700319 if (!mInputBufferIsDequeued[ix]) {
320 ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
321 mComponentName.c_str(), ix, bufferIx);
322 mediaBuffer->release();
323 return false;
324 }
Lajos Molnar09524832014-07-17 14:29:51 -0700325
326 // TRICKY: need buffer for the metadata, so instead, set
327 // codecBuffer to the same (though incorrect) buffer to
328 // avoid a memcpy into the codecBuffer
329 codecBuffer = buffer;
330 codecBuffer->setRange(
331 mediaBuffer->range_offset(),
332 mediaBuffer->range_length());
333 bufferIx = ix;
334 break;
335 }
336 }
337 CHECK(ix < mInputBuffers.size());
338 }
339 }
340
Andy Hungcf31f1e2014-09-23 14:59:01 -0700341
Lajos Molnar09524832014-07-17 14:29:51 -0700342
Lajos Molnar1cd13982014-01-17 15:12:51 -0800343 if (buffer == NULL /* includes !hasBuffer */) {
344 int32_t streamErr = ERROR_END_OF_STREAM;
345 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
346
347 if (streamErr == OK) {
348 /* buffers are returned to hold on to */
Wei Jia2245fc62014-10-02 15:12:25 -0700349 return true;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800350 }
351
352 // attempt to queue EOS
353 status_t err = mCodec->queueInputBuffer(
354 bufferIx,
355 0,
356 0,
357 0,
358 MediaCodec::BUFFER_FLAG_EOS);
Andy Hungcf31f1e2014-09-23 14:59:01 -0700359 if (err == OK) {
360 mInputBufferIsDequeued.editItemAt(bufferIx) = false;
361 } else if (streamErr == ERROR_END_OF_STREAM) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800362 streamErr = err;
363 // err will not be ERROR_END_OF_STREAM
364 }
365
366 if (streamErr != ERROR_END_OF_STREAM) {
Andy Hungcf31f1e2014-09-23 14:59:01 -0700367 ALOGE("Stream error for %s (err=%d), EOS %s queued",
368 mComponentName.c_str(),
369 streamErr,
370 err == OK ? "successfully" : "unsuccessfully");
Lajos Molnar1cd13982014-01-17 15:12:51 -0800371 handleError(streamErr);
372 }
373 } else {
374 int64_t timeUs = 0;
375 uint32_t flags = 0;
376 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
377
Lajos Molnar87603c02014-08-20 19:25:30 -0700378 int32_t eos, csd;
379 // we do not expect SYNCFRAME for decoder
Lajos Molnar1cd13982014-01-17 15:12:51 -0800380 if (buffer->meta()->findInt32("eos", &eos) && eos) {
381 flags |= MediaCodec::BUFFER_FLAG_EOS;
Lajos Molnar87603c02014-08-20 19:25:30 -0700382 } else if (buffer->meta()->findInt32("csd", &csd) && csd) {
383 flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800384 }
385
386 // copy into codec buffer
387 if (buffer != codecBuffer) {
388 CHECK_LE(buffer->size(), codecBuffer->capacity());
389 codecBuffer->setRange(0, buffer->size());
390 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
391 }
392
393 status_t err = mCodec->queueInputBuffer(
394 bufferIx,
395 codecBuffer->offset(),
396 codecBuffer->size(),
397 timeUs,
398 flags);
399 if (err != OK) {
Andy Hungcf31f1e2014-09-23 14:59:01 -0700400 if (mediaBuffer != NULL) {
401 mediaBuffer->release();
402 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800403 ALOGE("Failed to queue input buffer for %s (err=%d)",
404 mComponentName.c_str(), err);
405 handleError(err);
Andy Hungcf31f1e2014-09-23 14:59:01 -0700406 } else {
407 mInputBufferIsDequeued.editItemAt(bufferIx) = false;
408 if (mediaBuffer != NULL) {
409 CHECK(mMediaBuffers[bufferIx] == NULL);
410 mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
411 }
Lajos Molnar09524832014-07-17 14:29:51 -0700412 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800413 }
Wei Jia2245fc62014-10-02 15:12:25 -0700414 return true;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800415}
416
417bool NuPlayer::Decoder::handleAnOutputBuffer() {
418 size_t bufferIx = -1;
419 size_t offset;
420 size_t size;
421 int64_t timeUs;
422 uint32_t flags;
423 status_t res = mCodec->dequeueOutputBuffer(
424 &bufferIx, &offset, &size, &timeUs, &flags);
425
426 if (res != OK) {
427 ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
428 } else {
429 ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
430 mComponentName.c_str(), (int)bufferIx, timeUs, flags);
431 }
432
433 if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
434 res = mCodec->getOutputBuffers(&mOutputBuffers);
435 if (res != OK) {
436 ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
437 mComponentName.c_str(), res);
438 handleError(res);
439 return false;
440 }
441 // NuPlayer ignores this
442 return true;
443 } else if (res == INFO_FORMAT_CHANGED) {
444 sp<AMessage> format = new AMessage();
445 res = mCodec->getOutputFormat(&format);
446 if (res != OK) {
447 ALOGE("Failed to get output format for %s after INFO event (err=%d)",
448 mComponentName.c_str(), res);
449 handleError(res);
450 return false;
451 }
452
453 sp<AMessage> notify = mNotify->dup();
454 notify->setInt32("what", kWhatOutputFormatChanged);
455 notify->setMessage("format", format);
456 notify->post();
457 return true;
458 } else if (res == INFO_DISCONTINUITY) {
459 // nothing to do
460 return true;
461 } else if (res != OK) {
462 if (res != -EAGAIN) {
Andy Hungcf31f1e2014-09-23 14:59:01 -0700463 ALOGE("Failed to dequeue output buffer for %s (err=%d)",
464 mComponentName.c_str(), res);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800465 handleError(res);
466 }
467 return false;
468 }
469
470 CHECK_LT(bufferIx, mOutputBuffers.size());
471 sp<ABuffer> buffer = mOutputBuffers[bufferIx];
472 buffer->setRange(offset, size);
473 buffer->meta()->clear();
474 buffer->meta()->setInt64("timeUs", timeUs);
475 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
476 buffer->meta()->setInt32("eos", true);
477 }
478 // we do not expect CODECCONFIG or SYNCFRAME for decoder
479
480 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
481 reply->setSize("buffer-ix", bufferIx);
482 reply->setInt32("generation", mBufferGeneration);
483
484 sp<AMessage> notify = mNotify->dup();
485 notify->setInt32("what", kWhatDrainThisBuffer);
486 notify->setBuffer("buffer", buffer);
487 notify->setMessage("reply", reply);
488 notify->post();
489
490 // FIXME: This should be handled after rendering is complete,
491 // but Renderer needs it now
492 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
493 ALOGV("queueing eos [%s]", mComponentName.c_str());
494 sp<AMessage> notify = mNotify->dup();
495 notify->setInt32("what", kWhatEOS);
496 notify->setInt32("err", ERROR_END_OF_STREAM);
497 notify->post();
498 }
499 return true;
500}
501
502void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
503 status_t err;
504 int32_t render;
505 size_t bufferIx;
506 CHECK(msg->findSize("buffer-ix", &bufferIx));
507 if (msg->findInt32("render", &render) && render) {
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700508 int64_t timestampNs;
509 CHECK(msg->findInt64("timestampNs", &timestampNs));
510 err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800511 } else {
512 err = mCodec->releaseOutputBuffer(bufferIx);
513 }
514 if (err != OK) {
515 ALOGE("failed to release output buffer for %s (err=%d)",
516 mComponentName.c_str(), err);
517 handleError(err);
518 }
519}
520
521void NuPlayer::Decoder::onFlush() {
522 status_t err = OK;
523 if (mCodec != NULL) {
524 err = mCodec->flush();
Lajos Molnar87603c02014-08-20 19:25:30 -0700525 mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
Lajos Molnar1cd13982014-01-17 15:12:51 -0800526 ++mBufferGeneration;
527 }
528
529 if (err != OK) {
530 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
531 handleError(err);
532 return;
533 }
534
Lajos Molnar09524832014-07-17 14:29:51 -0700535 releaseAndResetMediaBuffers();
536
Lajos Molnar1cd13982014-01-17 15:12:51 -0800537 sp<AMessage> notify = mNotify->dup();
538 notify->setInt32("what", kWhatFlushCompleted);
539 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700540 mPaused = true;
541}
542
543void NuPlayer::Decoder::onResume() {
544 mPaused = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800545}
546
547void NuPlayer::Decoder::onShutdown() {
548 status_t err = OK;
549 if (mCodec != NULL) {
550 err = mCodec->release();
551 mCodec = NULL;
552 ++mBufferGeneration;
553
554 if (mNativeWindow != NULL) {
555 // reconnect to surface as MediaCodec disconnected from it
Wei Jia3fb9f682014-08-20 14:30:09 -0700556 status_t error =
Lajos Molnar1cd13982014-01-17 15:12:51 -0800557 native_window_api_connect(
558 mNativeWindow->getNativeWindow().get(),
Wei Jia3fb9f682014-08-20 14:30:09 -0700559 NATIVE_WINDOW_API_MEDIA);
560 ALOGW_IF(error != NO_ERROR,
561 "[%s] failed to connect to native window, error=%d",
562 mComponentName.c_str(), error);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800563 }
564 mComponentName = "decoder";
565 }
566
Lajos Molnar09524832014-07-17 14:29:51 -0700567 releaseAndResetMediaBuffers();
568
Lajos Molnar1cd13982014-01-17 15:12:51 -0800569 if (err != OK) {
570 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
571 handleError(err);
572 return;
573 }
574
575 sp<AMessage> notify = mNotify->dup();
576 notify->setInt32("what", kWhatShutdownCompleted);
577 notify->post();
Wei Jia704e7262014-06-04 16:21:56 -0700578 mPaused = true;
Andreas Huberf9334412010-12-15 15:17:42 -0800579}
580
581void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800582 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
583
Andreas Huberf9334412010-12-15 15:17:42 -0800584 switch (msg->what()) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800585 case kWhatConfigure:
586 {
587 sp<AMessage> format;
588 CHECK(msg->findMessage("format", &format));
589 onConfigure(format);
590 break;
591 }
592
Lajos Molnar87603c02014-08-20 19:25:30 -0700593 case kWhatUpdateFormat:
594 {
595 sp<AMessage> format;
596 CHECK(msg->findMessage("format", &format));
597 rememberCodecSpecificData(format);
598 break;
599 }
600
Lajos Molnar09524832014-07-17 14:29:51 -0700601 case kWhatGetInputBuffers:
602 {
603 uint32_t replyID;
604 CHECK(msg->senderAwaitsResponse(&replyID));
605
606 Vector<sp<ABuffer> > *dstBuffers;
607 CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
608
609 dstBuffers->clear();
610 for (size_t i = 0; i < mInputBuffers.size(); i++) {
611 dstBuffers->push(mInputBuffers[i]);
612 }
613
614 (new AMessage)->postReply(replyID);
615 break;
616 }
617
Andreas Huberf9334412010-12-15 15:17:42 -0800618 case kWhatCodecNotify:
619 {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800620 if (!isStaleReply(msg)) {
Wei Jia704e7262014-06-04 16:21:56 -0700621 if (!mPaused) {
622 while (handleAnInputBuffer()) {
623 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800624 }
Andreas Huberf9334412010-12-15 15:17:42 -0800625
Lajos Molnar1cd13982014-01-17 15:12:51 -0800626 while (handleAnOutputBuffer()) {
627 }
Andreas Huberf9334412010-12-15 15:17:42 -0800628 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800629
630 requestCodecNotification();
631 break;
632 }
633
634 case kWhatInputBufferFilled:
635 {
636 if (!isStaleReply(msg)) {
Wei Jia2245fc62014-10-02 15:12:25 -0700637 if (!mPendingInputMessages.empty()
638 || !onInputBufferFilled(msg)) {
639 mPendingInputMessages.push_back(msg);
640 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800641 }
Lajos Molnarb9b87fe2014-09-10 13:53:21 -0700642
Lajos Molnar1cd13982014-01-17 15:12:51 -0800643 break;
644 }
645
646 case kWhatRenderBuffer:
647 {
648 if (!isStaleReply(msg)) {
649 onRenderBuffer(msg);
650 }
651 break;
652 }
653
654 case kWhatFlush:
655 {
Lajos Molnar87603c02014-08-20 19:25:30 -0700656 sp<AMessage> format;
657 if (msg->findMessage("new-format", &format)) {
658 rememberCodecSpecificData(format);
659 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800660 onFlush();
661 break;
662 }
663
Wei Jia704e7262014-06-04 16:21:56 -0700664 case kWhatResume:
665 {
666 onResume();
667 break;
668 }
669
Lajos Molnar1cd13982014-01-17 15:12:51 -0800670 case kWhatShutdown:
671 {
672 onShutdown();
Andreas Huberf9334412010-12-15 15:17:42 -0800673 break;
674 }
675
676 default:
677 TRESPASS();
678 break;
679 }
680}
681
Lajos Molnar87603c02014-08-20 19:25:30 -0700682void NuPlayer::Decoder::signalFlush(const sp<AMessage> &format) {
683 sp<AMessage> msg = new AMessage(kWhatFlush, id());
684 if (format != NULL) {
685 msg->setMessage("new-format", format);
686 }
687 msg->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800688}
689
690void NuPlayer::Decoder::signalResume() {
Wei Jia704e7262014-06-04 16:21:56 -0700691 (new AMessage(kWhatResume, id()))->post();
Andreas Huberf9334412010-12-15 15:17:42 -0800692}
693
Andreas Huber3831a062010-12-21 10:22:33 -0800694void NuPlayer::Decoder::initiateShutdown() {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800695 (new AMessage(kWhatShutdown, id()))->post();
Andreas Huber3831a062010-12-21 10:22:33 -0800696}
697
Robert Shih6d0a94e2014-01-23 16:18:22 -0800698bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
699 if (targetFormat == NULL) {
700 return true;
701 }
702
703 AString mime;
704 if (!targetFormat->findString("mime", &mime)) {
705 return false;
706 }
707
708 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
709 // field-by-field comparison
710 const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
711 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
712 int32_t oldVal, newVal;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800713 if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
714 !targetFormat->findInt32(keys[i], &newVal) ||
715 oldVal != newVal) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800716 return false;
717 }
718 }
719
720 sp<ABuffer> oldBuf, newBuf;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800721 if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
722 targetFormat->findBuffer("csd-0", &newBuf)) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800723 if (oldBuf->size() != newBuf->size()) {
724 return false;
725 }
726 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
727 }
728 }
729 return false;
730}
731
732bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800733 if (mOutputFormat == NULL) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800734 return false;
735 }
736
737 if (targetFormat == NULL) {
738 return true;
739 }
740
741 AString oldMime, newMime;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800742 if (!mOutputFormat->findString("mime", &oldMime)
Robert Shih6d0a94e2014-01-23 16:18:22 -0800743 || !targetFormat->findString("mime", &newMime)
744 || !(oldMime == newMime)) {
745 return false;
746 }
747
748 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
749 bool seamless;
750 if (audio) {
751 seamless = supportsSeamlessAudioFormatChange(targetFormat);
752 } else {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800753 int32_t isAdaptive;
754 seamless = (mCodec != NULL &&
755 mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
756 isAdaptive);
Robert Shih6d0a94e2014-01-23 16:18:22 -0800757 }
758
759 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
760 return seamless;
761}
762
Chong Zhangb86e68f2014-08-01 13:46:53 -0700763struct CCData {
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700764 CCData(uint8_t type, uint8_t data1, uint8_t data2)
765 : mType(type), mData1(data1), mData2(data2) {
766 }
Chong Zhangb86e68f2014-08-01 13:46:53 -0700767 bool getChannel(size_t *channel) const {
768 if (mData1 >= 0x10 && mData1 <= 0x1f) {
769 *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0);
770 return true;
771 }
772 return false;
773 }
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700774
775 uint8_t mType;
776 uint8_t mData1;
777 uint8_t mData2;
778};
779
Chong Zhangb86e68f2014-08-01 13:46:53 -0700780static bool isNullPad(CCData *cc) {
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700781 return cc->mData1 < 0x10 && cc->mData2 < 0x10;
782}
783
Chong Zhangb86e68f2014-08-01 13:46:53 -0700784static void dumpBytePair(const sp<ABuffer> &ccBuf) {
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700785 size_t offset = 0;
786 AString out;
787
788 while (offset < ccBuf->size()) {
789 char tmp[128];
790
791 CCData *cc = (CCData *) (ccBuf->data() + offset);
792
793 if (isNullPad(cc)) {
794 // 1 null pad or XDS metadata, ignore
795 offset += sizeof(CCData);
796 continue;
797 }
798
799 if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
800 // 2 basic chars
801 sprintf(tmp, "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
802 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
803 && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
804 // 1 special char
805 sprintf(tmp, "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
806 } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
807 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
808 // 1 Spanish/French char
809 sprintf(tmp, "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
810 } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
811 && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
812 // 1 Portuguese/German/Danish char
813 sprintf(tmp, "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
814 } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
815 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
816 // Mid-Row Codes (Table 69)
817 sprintf(tmp, "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
818 } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
819 && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
820 ||
821 ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
822 && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
823 // Misc Control Codes (Table 70)
824 sprintf(tmp, "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
825 } else if ((cc->mData1 & 0x70) == 0x10
826 && (cc->mData2 & 0x40) == 0x40
827 && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
828 // Preamble Address Codes (Table 71)
829 sprintf(tmp, "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
830 } else {
831 sprintf(tmp, "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
832 }
833
834 if (out.size() > 0) {
835 out.append(", ");
836 }
837
838 out.append(tmp);
839
840 offset += sizeof(CCData);
841 }
842
843 ALOGI("%s", out.c_str());
844}
845
Chong Zhangb86e68f2014-08-01 13:46:53 -0700846NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
847 : mNotify(notify),
848 mCurrentChannel(0),
849 mSelectedTrack(-1) {
850 for (size_t i = 0; i < sizeof(mTrackIndices)/sizeof(mTrackIndices[0]); ++i) {
851 mTrackIndices[i] = -1;
852 }
853}
854
855size_t NuPlayer::CCDecoder::getTrackCount() const {
856 return mFoundChannels.size();
857}
858
859sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
860 if (!isTrackValid(index)) {
861 return NULL;
862 }
863
864 sp<AMessage> format = new AMessage();
865
866 format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
867 format->setString("language", "und");
868 format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
869 //CC1, field 0 channel 0
870 bool isDefaultAuto = (mFoundChannels[index] == 0);
871 format->setInt32("auto", isDefaultAuto);
872 format->setInt32("default", isDefaultAuto);
873 format->setInt32("forced", 0);
874
875 return format;
876}
877
878status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
879 if (!isTrackValid(index)) {
880 return BAD_VALUE;
881 }
882
883 if (select) {
884 if (mSelectedTrack == (ssize_t)index) {
885 ALOGE("track %zu already selected", index);
886 return BAD_VALUE;
887 }
888 ALOGV("selected track %zu", index);
889 mSelectedTrack = index;
890 } else {
891 if (mSelectedTrack != (ssize_t)index) {
892 ALOGE("track %zu is not selected", index);
893 return BAD_VALUE;
894 }
895 ALOGV("unselected track %zu", index);
896 mSelectedTrack = -1;
897 }
898
899 return OK;
900}
901
902bool NuPlayer::CCDecoder::isSelected() const {
903 return mSelectedTrack >= 0 && mSelectedTrack < (int32_t) getTrackCount();
904}
905
906bool NuPlayer::CCDecoder::isTrackValid(size_t index) const {
907 return index < getTrackCount();
908}
909
910int32_t NuPlayer::CCDecoder::getTrackIndex(size_t channel) const {
911 if (channel < sizeof(mTrackIndices)/sizeof(mTrackIndices[0])) {
912 return mTrackIndices[channel];
913 }
914 return -1;
915}
916
917// returns true if a new CC track is found
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700918bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
919 int64_t timeUs;
920 CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
921
922 sp<ABuffer> sei;
923 if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
924 return false;
925 }
926
Chong Zhangb86e68f2014-08-01 13:46:53 -0700927 bool trackAdded = false;
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700928
Chong Zhang862f8452014-06-26 19:55:23 -0700929 NALBitReader br(sei->data() + 1, sei->size() - 1);
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700930 // sei_message()
Chong Zhang862f8452014-06-26 19:55:23 -0700931 while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700932 uint32_t payload_type = 0;
933 size_t payload_size = 0;
934 uint8_t last_byte;
935
936 do {
937 last_byte = br.getBits(8);
938 payload_type += last_byte;
939 } while (last_byte == 0xFF);
940
941 do {
942 last_byte = br.getBits(8);
943 payload_size += last_byte;
944 } while (last_byte == 0xFF);
945
946 // sei_payload()
947 if (payload_type == 4) {
948 // user_data_registered_itu_t_t35()
949
950 // ATSC A/72: 6.4.2
951 uint8_t itu_t_t35_country_code = br.getBits(8);
952 uint16_t itu_t_t35_provider_code = br.getBits(16);
953 uint32_t user_identifier = br.getBits(32);
954 uint8_t user_data_type_code = br.getBits(8);
955
956 payload_size -= 1 + 2 + 4 + 1;
957
958 if (itu_t_t35_country_code == 0xB5
959 && itu_t_t35_provider_code == 0x0031
960 && user_identifier == 'GA94'
961 && user_data_type_code == 0x3) {
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700962 // MPEG_cc_data()
963 // ATSC A/53 Part 4: 6.2.3.1
964 br.skipBits(1); //process_em_data_flag
965 bool process_cc_data_flag = br.getBits(1);
966 br.skipBits(1); //additional_data_flag
967 size_t cc_count = br.getBits(5);
968 br.skipBits(8); // em_data;
969 payload_size -= 2;
970
971 if (process_cc_data_flag) {
972 AString out;
973
974 sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
975 ccBuf->setRange(0, 0);
976
977 for (size_t i = 0; i < cc_count; i++) {
978 uint8_t marker = br.getBits(5);
979 CHECK_EQ(marker, 0x1f);
980
981 bool cc_valid = br.getBits(1);
982 uint8_t cc_type = br.getBits(2);
983 // remove odd parity bit
984 uint8_t cc_data_1 = br.getBits(8) & 0x7f;
985 uint8_t cc_data_2 = br.getBits(8) & 0x7f;
986
987 if (cc_valid
988 && (cc_type == 0 || cc_type == 1)) {
989 CCData cc(cc_type, cc_data_1, cc_data_2);
990 if (!isNullPad(&cc)) {
Chong Zhangb86e68f2014-08-01 13:46:53 -0700991 size_t channel;
992 if (cc.getChannel(&channel) && getTrackIndex(channel) < 0) {
993 mTrackIndices[channel] = mFoundChannels.size();
994 mFoundChannels.push_back(channel);
995 trackAdded = true;
996 }
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700997 memcpy(ccBuf->data() + ccBuf->size(),
998 (void *)&cc, sizeof(cc));
999 ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
1000 }
1001 }
1002 }
1003 payload_size -= cc_count * 3;
1004
1005 mCCMap.add(timeUs, ccBuf);
1006 break;
1007 }
1008 } else {
1009 ALOGV("Malformed SEI payload type 4");
1010 }
1011 } else {
1012 ALOGV("Unsupported SEI payload type %d", payload_type);
1013 }
1014
1015 // skipping remaining bits of this payload
1016 br.skipBits(payload_size * 8);
1017 }
1018
Chong Zhangb86e68f2014-08-01 13:46:53 -07001019 return trackAdded;
1020}
1021
1022sp<ABuffer> NuPlayer::CCDecoder::filterCCBuf(
1023 const sp<ABuffer> &ccBuf, size_t index) {
1024 sp<ABuffer> filteredCCBuf = new ABuffer(ccBuf->size());
1025 filteredCCBuf->setRange(0, 0);
1026
1027 size_t cc_count = ccBuf->size() / sizeof(CCData);
1028 const CCData* cc_data = (const CCData*)ccBuf->data();
1029 for (size_t i = 0; i < cc_count; ++i) {
1030 size_t channel;
1031 if (cc_data[i].getChannel(&channel)) {
1032 mCurrentChannel = channel;
1033 }
1034 if (mCurrentChannel == mFoundChannels[index]) {
1035 memcpy(filteredCCBuf->data() + filteredCCBuf->size(),
1036 (void *)&cc_data[i], sizeof(CCData));
1037 filteredCCBuf->setRange(0, filteredCCBuf->size() + sizeof(CCData));
1038 }
1039 }
1040
1041 return filteredCCBuf;
Chong Zhanga7fa1d92014-06-11 14:49:23 -07001042}
1043
1044void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
Chong Zhangb86e68f2014-08-01 13:46:53 -07001045 if (extractFromSEI(accessUnit)) {
Chong Zhanga7fa1d92014-06-11 14:49:23 -07001046 ALOGI("Found CEA-608 track");
1047 sp<AMessage> msg = mNotify->dup();
1048 msg->setInt32("what", kWhatTrackAdded);
1049 msg->post();
1050 }
1051 // TODO: extract CC from other sources
1052}
1053
1054void NuPlayer::CCDecoder::display(int64_t timeUs) {
Chong Zhangb86e68f2014-08-01 13:46:53 -07001055 if (!isTrackValid(mSelectedTrack)) {
1056 ALOGE("Could not find current track(index=%d)", mSelectedTrack);
1057 return;
1058 }
1059
Chong Zhanga7fa1d92014-06-11 14:49:23 -07001060 ssize_t index = mCCMap.indexOfKey(timeUs);
1061 if (index < 0) {
1062 ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
1063 return;
1064 }
1065
Chong Zhangb86e68f2014-08-01 13:46:53 -07001066 sp<ABuffer> ccBuf = filterCCBuf(mCCMap.valueAt(index), mSelectedTrack);
Chong Zhanga7fa1d92014-06-11 14:49:23 -07001067
1068 if (ccBuf->size() > 0) {
1069#if 0
1070 dumpBytePair(ccBuf);
1071#endif
1072
1073 ccBuf->meta()->setInt32("trackIndex", mSelectedTrack);
1074 ccBuf->meta()->setInt64("timeUs", timeUs);
1075 ccBuf->meta()->setInt64("durationUs", 0ll);
1076
1077 sp<AMessage> msg = mNotify->dup();
1078 msg->setInt32("what", kWhatClosedCaptionData);
1079 msg->setBuffer("buffer", ccBuf);
1080 msg->post();
1081 }
1082
1083 // remove all entries before timeUs
1084 mCCMap.removeItemsAt(0, index + 1);
1085}
1086
Chong Zhangb86e68f2014-08-01 13:46:53 -07001087void NuPlayer::CCDecoder::flush() {
1088 mCCMap.clear();
1089}
1090
Andreas Huberf9334412010-12-15 15:17:42 -08001091} // namespace android
1092