blob: c649c62d24212b8b9d980be5edd6e7fea4d0a224 [file] [log] [blame]
Andreas Huberf9334412010-12-15 15:17:42 -08001/*
Chong Zhang7137ec72014-11-12 16:41:05 -08002 * Copyright 2014 The Android Open Source Project
Andreas Huberf9334412010-12-15 15:17:42 -08003 *
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
Chong Zhang7137ec72014-11-12 16:41:05 -080022#include "NuPlayerCCDecoder.h"
Andreas Huberf9334412010-12-15 15:17:42 -080023#include "NuPlayerDecoder.h"
Wei Jiac6cfd702014-11-11 16:33:20 -080024#include "NuPlayerRenderer.h"
25#include "NuPlayerSource.h"
26
Andy Hung288da022015-05-31 22:55:59 -070027#include <cutils/properties.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080028#include <media/ICrypto.h>
Andreas Huberf9334412010-12-15 15:17:42 -080029#include <media/stagefright/foundation/ABuffer.h>
30#include <media/stagefright/foundation/ADebug.h>
Andreas Huber5bc087c2010-12-23 10:27:40 -080031#include <media/stagefright/foundation/AMessage.h>
Lajos Molnar09524832014-07-17 14:29:51 -070032#include <media/stagefright/MediaBuffer.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080033#include <media/stagefright/MediaCodec.h>
Andreas Huberf9334412010-12-15 15:17:42 -080034#include <media/stagefright/MediaDefs.h>
Lajos Molnar1cd13982014-01-17 15:12:51 -080035#include <media/stagefright/MediaErrors.h>
Andreas Huberf9334412010-12-15 15:17:42 -080036
Lajos Molnar1de1e252015-04-30 18:18:34 -070037#include <gui/Surface.h>
38
Chong Zhang7137ec72014-11-12 16:41:05 -080039#include "avc_utils.h"
40#include "ATSParser.h"
41
Andreas Huberf9334412010-12-15 15:17:42 -080042namespace android {
43
Andy Hung288da022015-05-31 22:55:59 -070044static inline bool getAudioDeepBufferSetting() {
45 return property_get_bool("media.stagefright.audio.deep", false /* default_value */);
46}
47
Andreas Huberf9334412010-12-15 15:17:42 -080048NuPlayer::Decoder::Decoder(
Glenn Kasten11731182011-02-08 17:26:17 -080049 const sp<AMessage> &notify,
Wei Jiac6cfd702014-11-11 16:33:20 -080050 const sp<Source> &source,
51 const sp<Renderer> &renderer,
Lajos Molnar1de1e252015-04-30 18:18:34 -070052 const sp<Surface> &surface,
Chong Zhang7137ec72014-11-12 16:41:05 -080053 const sp<CCDecoder> &ccDecoder)
Andy Hung202bce12014-12-03 11:47:36 -080054 : DecoderBase(notify),
Lajos Molnar1de1e252015-04-30 18:18:34 -070055 mSurface(surface),
Wei Jiac6cfd702014-11-11 16:33:20 -080056 mSource(source),
57 mRenderer(renderer),
Chong Zhang7137ec72014-11-12 16:41:05 -080058 mCCDecoder(ccDecoder),
Wei Jiac6cfd702014-11-11 16:33:20 -080059 mSkipRenderingUntilMediaTimeUs(-1ll),
Chong Zhang7137ec72014-11-12 16:41:05 -080060 mNumFramesTotal(0ll),
61 mNumFramesDropped(0ll),
62 mIsAudio(true),
63 mIsVideoAVC(false),
64 mIsSecure(false),
65 mFormatChangePending(false),
Chong Zhang66704af2015-03-03 19:32:35 -080066 mTimeChangePending(false),
Wei Jia704e7262014-06-04 16:21:56 -070067 mPaused(true),
Chong Zhangf8d71772014-11-26 15:08:34 -080068 mResumePending(false),
Lajos Molnar1cd13982014-01-17 15:12:51 -080069 mComponentName("decoder") {
Lajos Molnar1cd13982014-01-17 15:12:51 -080070 mCodecLooper = new ALooper;
Marco Nelissen9e2b7912014-08-18 16:13:03 -070071 mCodecLooper->setName("NPDecoder-CL");
Lajos Molnar1cd13982014-01-17 15:12:51 -080072 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
Andreas Huberf9334412010-12-15 15:17:42 -080073}
74
75NuPlayer::Decoder::~Decoder() {
Ronghua Wufaeb0f22015-05-21 12:20:21 -070076 mCodec->release();
Wei Jia4923cee2014-09-24 14:25:19 -070077 releaseAndResetMediaBuffers();
Andreas Huberf9334412010-12-15 15:17:42 -080078}
79
Chong Zhang7137ec72014-11-12 16:41:05 -080080void NuPlayer::Decoder::getStats(
81 int64_t *numFramesTotal,
82 int64_t *numFramesDropped) const {
83 *numFramesTotal = mNumFramesTotal;
84 *numFramesDropped = mNumFramesDropped;
Lajos Molnar09524832014-07-17 14:29:51 -070085}
86
Chong Zhang7137ec72014-11-12 16:41:05 -080087void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
88 ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
89
90 switch (msg->what()) {
91 case kWhatCodecNotify:
92 {
Chong Zhang3b032b32015-04-17 15:49:06 -070093 int32_t cbID;
94 CHECK(msg->findInt32("callbackID", &cbID));
95
96 ALOGV("[%s] kWhatCodecNotify: cbID = %d, paused = %d",
97 mIsAudio ? "audio" : "video", cbID, mPaused);
98
Marco Nelissen421f47c2015-03-25 14:40:32 -070099 if (mPaused) {
100 break;
Chong Zhang7137ec72014-11-12 16:41:05 -0800101 }
102
Marco Nelissen421f47c2015-03-25 14:40:32 -0700103 switch (cbID) {
104 case MediaCodec::CB_INPUT_AVAILABLE:
105 {
106 int32_t index;
107 CHECK(msg->findInt32("index", &index));
108
109 handleAnInputBuffer(index);
110 break;
111 }
112
113 case MediaCodec::CB_OUTPUT_AVAILABLE:
114 {
115 int32_t index;
116 size_t offset;
117 size_t size;
118 int64_t timeUs;
119 int32_t flags;
120
121 CHECK(msg->findInt32("index", &index));
122 CHECK(msg->findSize("offset", &offset));
123 CHECK(msg->findSize("size", &size));
124 CHECK(msg->findInt64("timeUs", &timeUs));
125 CHECK(msg->findInt32("flags", &flags));
126
127 handleAnOutputBuffer(index, offset, size, timeUs, flags);
128 break;
129 }
130
131 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
132 {
133 sp<AMessage> format;
134 CHECK(msg->findMessage("format", &format));
135
136 handleOutputFormatChange(format);
137 break;
138 }
139
140 case MediaCodec::CB_ERROR:
141 {
142 status_t err;
143 CHECK(msg->findInt32("err", &err));
144 ALOGE("Decoder (%s) reported error : 0x%x",
145 mIsAudio ? "audio" : "video", err);
146
147 handleError(err);
148 break;
149 }
150
151 default:
152 {
153 TRESPASS();
154 break;
155 }
156 }
157
Lajos Molnar87603c02014-08-20 19:25:30 -0700158 break;
159 }
Chong Zhang7137ec72014-11-12 16:41:05 -0800160
161 case kWhatRenderBuffer:
162 {
163 if (!isStaleReply(msg)) {
164 onRenderBuffer(msg);
165 }
166 break;
167 }
168
169 default:
170 DecoderBase::onMessageReceived(msg);
171 break;
Lajos Molnar87603c02014-08-20 19:25:30 -0700172 }
173}
174
Lajos Molnar1cd13982014-01-17 15:12:51 -0800175void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
Andreas Huberf9334412010-12-15 15:17:42 -0800176 CHECK(mCodec == NULL);
Andreas Huberf9334412010-12-15 15:17:42 -0800177
Chong Zhang7137ec72014-11-12 16:41:05 -0800178 mFormatChangePending = false;
Chong Zhang66704af2015-03-03 19:32:35 -0800179 mTimeChangePending = false;
Chong Zhang7137ec72014-11-12 16:41:05 -0800180
Lajos Molnar1cd13982014-01-17 15:12:51 -0800181 ++mBufferGeneration;
182
Andreas Huber84066782011-08-16 09:34:26 -0700183 AString mime;
184 CHECK(format->findString("mime", &mime));
Andreas Huberf9334412010-12-15 15:17:42 -0800185
Chong Zhang7137ec72014-11-12 16:41:05 -0800186 mIsAudio = !strncasecmp("audio/", mime.c_str(), 6);
187 mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
188
Lajos Molnar1cd13982014-01-17 15:12:51 -0800189 mComponentName = mime;
190 mComponentName.append(" decoder");
Lajos Molnar1de1e252015-04-30 18:18:34 -0700191 ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get());
Lajos Molnar1cd13982014-01-17 15:12:51 -0800192
193 mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
Lajos Molnar09524832014-07-17 14:29:51 -0700194 int32_t secure = 0;
195 if (format->findInt32("secure", &secure) && secure != 0) {
196 if (mCodec != NULL) {
197 mCodec->getName(&mComponentName);
198 mComponentName.append(".secure");
199 mCodec->release();
200 ALOGI("[%s] creating", mComponentName.c_str());
201 mCodec = MediaCodec::CreateByComponentName(
202 mCodecLooper, mComponentName.c_str());
203 }
204 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800205 if (mCodec == NULL) {
Lajos Molnar09524832014-07-17 14:29:51 -0700206 ALOGE("Failed to create %s%s decoder",
207 (secure ? "secure " : ""), mime.c_str());
Lajos Molnar1cd13982014-01-17 15:12:51 -0800208 handleError(UNKNOWN_ERROR);
209 return;
210 }
Chong Zhang7137ec72014-11-12 16:41:05 -0800211 mIsSecure = secure;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800212
213 mCodec->getName(&mComponentName);
214
Lajos Molnar14986f62014-09-15 11:04:44 -0700215 status_t err;
Lajos Molnar1de1e252015-04-30 18:18:34 -0700216 if (mSurface != NULL) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800217 // disconnect from surface as MediaCodec will reconnect
Lajos Molnar14986f62014-09-15 11:04:44 -0700218 err = native_window_api_disconnect(
Lajos Molnar1de1e252015-04-30 18:18:34 -0700219 mSurface.get(), NATIVE_WINDOW_API_MEDIA);
Lajos Molnar14986f62014-09-15 11:04:44 -0700220 // We treat this as a warning, as this is a preparatory step.
221 // Codec will try to connect to the surface, which is where
222 // any error signaling will occur.
223 ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800224 }
Lajos Molnar14986f62014-09-15 11:04:44 -0700225 err = mCodec->configure(
Lajos Molnar1de1e252015-04-30 18:18:34 -0700226 format, mSurface, NULL /* crypto */, 0 /* flags */);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800227 if (err != OK) {
228 ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
Andy Hung2abde2c2014-09-30 14:40:32 -0700229 mCodec->release();
230 mCodec.clear();
Lajos Molnar1cd13982014-01-17 15:12:51 -0800231 handleError(err);
232 return;
233 }
Lajos Molnar87603c02014-08-20 19:25:30 -0700234 rememberCodecSpecificData(format);
235
Lajos Molnar1cd13982014-01-17 15:12:51 -0800236 // the following should work in configured state
237 CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
238 CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
239
Marco Nelissen421f47c2015-03-25 14:40:32 -0700240 sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
241 mCodec->setCallback(reply);
242
Lajos Molnar1cd13982014-01-17 15:12:51 -0800243 err = mCodec->start();
244 if (err != OK) {
245 ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
Andy Hung2abde2c2014-09-30 14:40:32 -0700246 mCodec->release();
247 mCodec.clear();
Lajos Molnar1cd13982014-01-17 15:12:51 -0800248 handleError(err);
249 return;
Andreas Huberf9334412010-12-15 15:17:42 -0800250 }
251
Lajos Molnar09524832014-07-17 14:29:51 -0700252 releaseAndResetMediaBuffers();
Marco Nelissen421f47c2015-03-25 14:40:32 -0700253
Wei Jia704e7262014-06-04 16:21:56 -0700254 mPaused = false;
Chong Zhangf8d71772014-11-26 15:08:34 -0800255 mResumePending = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800256}
Andreas Huber078cfcf2011-09-15 12:25:04 -0700257
Ronghua Wu8db88132015-04-22 13:51:35 -0700258void NuPlayer::Decoder::onSetParameters(const sp<AMessage> &params) {
259 if (mCodec == NULL) {
260 ALOGW("onSetParameters called before codec is created.");
261 return;
262 }
263 mCodec->setParameters(params);
264}
265
Chong Zhang7137ec72014-11-12 16:41:05 -0800266void NuPlayer::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
267 bool hadNoRenderer = (mRenderer == NULL);
268 mRenderer = renderer;
269 if (hadNoRenderer && mRenderer != NULL) {
Lajos Molnare6109e22015-04-10 17:18:22 -0700270 // this means that the widevine legacy source is ready
271 onRequestInputBuffers();
Chong Zhang7137ec72014-11-12 16:41:05 -0800272 }
273}
274
275void NuPlayer::Decoder::onGetInputBuffers(
276 Vector<sp<ABuffer> > *dstBuffers) {
Lajos Molnare6109e22015-04-10 17:18:22 -0700277 CHECK_EQ((status_t)OK, mCodec->getWidevineLegacyBuffers(dstBuffers));
Chong Zhang7137ec72014-11-12 16:41:05 -0800278}
279
Chong Zhangf8d71772014-11-26 15:08:34 -0800280void NuPlayer::Decoder::onResume(bool notifyComplete) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800281 mPaused = false;
Chong Zhangf8d71772014-11-26 15:08:34 -0800282
283 if (notifyComplete) {
284 mResumePending = true;
285 }
Marco Nelissen421f47c2015-03-25 14:40:32 -0700286 mCodec->start();
Chong Zhang7137ec72014-11-12 16:41:05 -0800287}
288
Chong Zhang66704af2015-03-03 19:32:35 -0800289void NuPlayer::Decoder::doFlush(bool notifyComplete) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800290 if (mCCDecoder != NULL) {
291 mCCDecoder->flush();
292 }
293
294 if (mRenderer != NULL) {
295 mRenderer->flush(mIsAudio, notifyComplete);
296 mRenderer->signalTimeDiscontinuity();
297 }
298
299 status_t err = OK;
300 if (mCodec != NULL) {
301 err = mCodec->flush();
302 mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
303 ++mBufferGeneration;
304 }
305
306 if (err != OK) {
307 ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
308 handleError(err);
309 // finish with posting kWhatFlushCompleted.
310 // we attempt to release the buffers even if flush fails.
311 }
312 releaseAndResetMediaBuffers();
Marco Nelissen421f47c2015-03-25 14:40:32 -0700313 mPaused = true;
Chong Zhang66704af2015-03-03 19:32:35 -0800314}
Chong Zhang7137ec72014-11-12 16:41:05 -0800315
Marco Nelissen421f47c2015-03-25 14:40:32 -0700316
Chong Zhang66704af2015-03-03 19:32:35 -0800317void NuPlayer::Decoder::onFlush() {
318 doFlush(true);
319
320 if (isDiscontinuityPending()) {
321 // This could happen if the client starts seeking/shutdown
322 // after we queued an EOS for discontinuities.
323 // We can consider discontinuity handled.
324 finishHandleDiscontinuity(false /* flushOnTimeChange */);
Chong Zhang7137ec72014-11-12 16:41:05 -0800325 }
Chong Zhang66704af2015-03-03 19:32:35 -0800326
327 sp<AMessage> notify = mNotify->dup();
328 notify->setInt32("what", kWhatFlushCompleted);
329 notify->post();
Chong Zhang7137ec72014-11-12 16:41:05 -0800330}
331
332void NuPlayer::Decoder::onShutdown(bool notifyComplete) {
333 status_t err = OK;
Chong Zhangf8d71772014-11-26 15:08:34 -0800334
335 // if there is a pending resume request, notify complete now
336 notifyResumeCompleteIfNecessary();
337
Chong Zhang7137ec72014-11-12 16:41:05 -0800338 if (mCodec != NULL) {
339 err = mCodec->release();
340 mCodec = NULL;
341 ++mBufferGeneration;
342
Lajos Molnar1de1e252015-04-30 18:18:34 -0700343 if (mSurface != NULL) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800344 // reconnect to surface as MediaCodec disconnected from it
345 status_t error =
Lajos Molnar1de1e252015-04-30 18:18:34 -0700346 native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_MEDIA);
Chong Zhang7137ec72014-11-12 16:41:05 -0800347 ALOGW_IF(error != NO_ERROR,
348 "[%s] failed to connect to native window, error=%d",
349 mComponentName.c_str(), error);
350 }
351 mComponentName = "decoder";
352 }
353
354 releaseAndResetMediaBuffers();
355
356 if (err != OK) {
357 ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
358 handleError(err);
359 // finish with posting kWhatShutdownCompleted.
360 }
361
362 if (notifyComplete) {
363 sp<AMessage> notify = mNotify->dup();
364 notify->setInt32("what", kWhatShutdownCompleted);
365 notify->post();
366 mPaused = true;
367 }
368}
369
Chong Zhang3b032b32015-04-17 15:49:06 -0700370/*
371 * returns true if we should request more data
372 */
373bool NuPlayer::Decoder::doRequestBuffers() {
Lajos Molnare6109e22015-04-10 17:18:22 -0700374 // mRenderer is only NULL if we have a legacy widevine source that
375 // is not yet ready. In this case we must not fetch input.
376 if (isDiscontinuityPending() || mRenderer == NULL) {
Chong Zhang3b032b32015-04-17 15:49:06 -0700377 return false;
Chong Zhang7137ec72014-11-12 16:41:05 -0800378 }
379 status_t err = OK;
Chong Zhang66704af2015-03-03 19:32:35 -0800380 while (err == OK && !mDequeuedInputBuffers.empty()) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800381 size_t bufferIx = *mDequeuedInputBuffers.begin();
382 sp<AMessage> msg = new AMessage();
383 msg->setSize("buffer-ix", bufferIx);
384 err = fetchInputData(msg);
Chong Zhang66704af2015-03-03 19:32:35 -0800385 if (err != OK && err != ERROR_END_OF_STREAM) {
386 // if EOS, need to queue EOS buffer
Chong Zhang7137ec72014-11-12 16:41:05 -0800387 break;
388 }
389 mDequeuedInputBuffers.erase(mDequeuedInputBuffers.begin());
390
391 if (!mPendingInputMessages.empty()
392 || !onInputBufferFetched(msg)) {
393 mPendingInputMessages.push_back(msg);
Lajos Molnar09524832014-07-17 14:29:51 -0700394 }
395 }
Chong Zhang7137ec72014-11-12 16:41:05 -0800396
Chong Zhang3b032b32015-04-17 15:49:06 -0700397 return err == -EWOULDBLOCK
398 && mSource->feedMoreTSData() == OK;
Lajos Molnar09524832014-07-17 14:29:51 -0700399}
400
Marco Nelissen421f47c2015-03-25 14:40:32 -0700401void NuPlayer::Decoder::handleError(int32_t err)
402{
403 // We cannot immediately release the codec due to buffers still outstanding
404 // in the renderer. We signal to the player the error so it can shutdown/release the
405 // decoder after flushing and increment the generation to discard unnecessary messages.
406
407 ++mBufferGeneration;
408
409 sp<AMessage> notify = mNotify->dup();
410 notify->setInt32("what", kWhatError);
411 notify->setInt32("err", err);
412 notify->post();
413}
414
415bool NuPlayer::Decoder::handleAnInputBuffer(size_t index) {
Chong Zhang66704af2015-03-03 19:32:35 -0800416 if (isDiscontinuityPending()) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800417 return false;
418 }
Marco Nelissen421f47c2015-03-25 14:40:32 -0700419
420 sp<ABuffer> buffer;
421 mCodec->getInputBuffer(index, &buffer);
422
Wei Jia6301a5e2015-05-13 13:15:18 -0700423 if (buffer == NULL) {
424 handleError(UNKNOWN_ERROR);
425 return false;
426 }
427
Marco Nelissen421f47c2015-03-25 14:40:32 -0700428 if (index >= mInputBuffers.size()) {
429 for (size_t i = mInputBuffers.size(); i <= index; ++i) {
430 mInputBuffers.add();
431 mMediaBuffers.add();
432 mInputBufferIsDequeued.add();
433 mMediaBuffers.editItemAt(i) = NULL;
434 mInputBufferIsDequeued.editItemAt(i) = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800435 }
Andreas Huber078cfcf2011-09-15 12:25:04 -0700436 }
Marco Nelissen421f47c2015-03-25 14:40:32 -0700437 mInputBuffers.editItemAt(index) = buffer;
Andreas Huber078cfcf2011-09-15 12:25:04 -0700438
Marco Nelissen421f47c2015-03-25 14:40:32 -0700439 //CHECK_LT(bufferIx, mInputBuffers.size());
Andreas Huberf9334412010-12-15 15:17:42 -0800440
Marco Nelissen421f47c2015-03-25 14:40:32 -0700441 if (mMediaBuffers[index] != NULL) {
442 mMediaBuffers[index]->release();
443 mMediaBuffers.editItemAt(index) = NULL;
Lajos Molnar09524832014-07-17 14:29:51 -0700444 }
Marco Nelissen421f47c2015-03-25 14:40:32 -0700445 mInputBufferIsDequeued.editItemAt(index) = true;
Lajos Molnar09524832014-07-17 14:29:51 -0700446
Lajos Molnar87603c02014-08-20 19:25:30 -0700447 if (!mCSDsToSubmit.isEmpty()) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800448 sp<AMessage> msg = new AMessage();
Marco Nelissen421f47c2015-03-25 14:40:32 -0700449 msg->setSize("buffer-ix", index);
Chong Zhang7137ec72014-11-12 16:41:05 -0800450
Lajos Molnar87603c02014-08-20 19:25:30 -0700451 sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
452 ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
Chong Zhang7137ec72014-11-12 16:41:05 -0800453 msg->setBuffer("buffer", buffer);
Lajos Molnar87603c02014-08-20 19:25:30 -0700454 mCSDsToSubmit.removeAt(0);
Chong Zhang7137ec72014-11-12 16:41:05 -0800455 CHECK(onInputBufferFetched(msg));
Wei Jia2245fc62014-10-02 15:12:25 -0700456 return true;
457 }
458
459 while (!mPendingInputMessages.empty()) {
460 sp<AMessage> msg = *mPendingInputMessages.begin();
Chong Zhang7137ec72014-11-12 16:41:05 -0800461 if (!onInputBufferFetched(msg)) {
Wei Jia2245fc62014-10-02 15:12:25 -0700462 break;
463 }
464 mPendingInputMessages.erase(mPendingInputMessages.begin());
465 }
466
Marco Nelissen421f47c2015-03-25 14:40:32 -0700467 if (!mInputBufferIsDequeued.editItemAt(index)) {
Lajos Molnar87603c02014-08-20 19:25:30 -0700468 return true;
469 }
470
Marco Nelissen421f47c2015-03-25 14:40:32 -0700471 mDequeuedInputBuffers.push_back(index);
Chong Zhang7137ec72014-11-12 16:41:05 -0800472
473 onRequestInputBuffers();
Lajos Molnar1cd13982014-01-17 15:12:51 -0800474 return true;
475}
476
Marco Nelissen421f47c2015-03-25 14:40:32 -0700477bool NuPlayer::Decoder::handleAnOutputBuffer(
478 size_t index,
479 size_t offset,
480 size_t size,
481 int64_t timeUs,
482 int32_t flags) {
Marco Nelissen421f47c2015-03-25 14:40:32 -0700483// CHECK_LT(bufferIx, mOutputBuffers.size());
484 sp<ABuffer> buffer;
485 mCodec->getOutputBuffer(index, &buffer);
486
487 if (index >= mOutputBuffers.size()) {
488 for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
489 mOutputBuffers.add();
490 }
491 }
492
493 mOutputBuffers.editItemAt(index) = buffer;
494
Chong Zhang7137ec72014-11-12 16:41:05 -0800495 buffer->setRange(offset, size);
496 buffer->meta()->clear();
497 buffer->meta()->setInt64("timeUs", timeUs);
Chong Zhang66704af2015-03-03 19:32:35 -0800498
499 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
Chong Zhang7137ec72014-11-12 16:41:05 -0800500 // we do not expect CODECCONFIG or SYNCFRAME for decoder
501
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800502 sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
Marco Nelissen421f47c2015-03-25 14:40:32 -0700503 reply->setSize("buffer-ix", index);
Chong Zhang7137ec72014-11-12 16:41:05 -0800504 reply->setInt32("generation", mBufferGeneration);
505
Chong Zhang66704af2015-03-03 19:32:35 -0800506 if (eos) {
507 ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
508
509 buffer->meta()->setInt32("eos", true);
510 reply->setInt32("eos", true);
511 } else if (mSkipRenderingUntilMediaTimeUs >= 0) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800512 if (timeUs < mSkipRenderingUntilMediaTimeUs) {
513 ALOGV("[%s] dropping buffer at time %lld as requested.",
514 mComponentName.c_str(), (long long)timeUs);
515
516 reply->post();
517 return true;
518 }
519
520 mSkipRenderingUntilMediaTimeUs = -1;
521 }
522
Chong Zhangf8d71772014-11-26 15:08:34 -0800523 // wait until 1st frame comes out to signal resume complete
524 notifyResumeCompleteIfNecessary();
525
Chong Zhang7137ec72014-11-12 16:41:05 -0800526 if (mRenderer != NULL) {
527 // send the buffer to renderer.
528 mRenderer->queueBuffer(mIsAudio, buffer, reply);
Chong Zhang66704af2015-03-03 19:32:35 -0800529 if (eos && !isDiscontinuityPending()) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800530 mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
531 }
532 }
533
534 return true;
535}
536
Marco Nelissen421f47c2015-03-25 14:40:32 -0700537void NuPlayer::Decoder::handleOutputFormatChange(const sp<AMessage> &format) {
538 if (!mIsAudio) {
539 sp<AMessage> notify = mNotify->dup();
540 notify->setInt32("what", kWhatVideoSizeChanged);
541 notify->setMessage("format", format);
542 notify->post();
543 } else if (mRenderer != NULL) {
544 uint32_t flags;
545 int64_t durationUs;
546 bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
Andy Hung288da022015-05-31 22:55:59 -0700547 if (getAudioDeepBufferSetting() // override regardless of source duration
548 || (!hasVideo
549 && mSource->getDuration(&durationUs) == OK
550 && durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US)) {
Marco Nelissen421f47c2015-03-25 14:40:32 -0700551 flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
552 } else {
553 flags = AUDIO_OUTPUT_FLAG_NONE;
554 }
555
556 mRenderer->openAudioSink(
557 format, false /* offloadOnly */, hasVideo, flags, NULL /* isOffloaed */);
558 }
559}
560
Chong Zhang7137ec72014-11-12 16:41:05 -0800561void NuPlayer::Decoder::releaseAndResetMediaBuffers() {
562 for (size_t i = 0; i < mMediaBuffers.size(); i++) {
563 if (mMediaBuffers[i] != NULL) {
564 mMediaBuffers[i]->release();
565 mMediaBuffers.editItemAt(i) = NULL;
566 }
567 }
568 mMediaBuffers.resize(mInputBuffers.size());
569 for (size_t i = 0; i < mMediaBuffers.size(); i++) {
570 mMediaBuffers.editItemAt(i) = NULL;
571 }
572 mInputBufferIsDequeued.clear();
573 mInputBufferIsDequeued.resize(mInputBuffers.size());
574 for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
575 mInputBufferIsDequeued.editItemAt(i) = false;
576 }
577
578 mPendingInputMessages.clear();
579 mDequeuedInputBuffers.clear();
580 mSkipRenderingUntilMediaTimeUs = -1;
581}
582
583void NuPlayer::Decoder::requestCodecNotification() {
Chong Zhang7137ec72014-11-12 16:41:05 -0800584 if (mCodec != NULL) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800585 sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
Chong Zhang7137ec72014-11-12 16:41:05 -0800586 reply->setInt32("generation", mBufferGeneration);
587 mCodec->requestActivityNotification(reply);
588 }
589}
590
591bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
592 int32_t generation;
593 CHECK(msg->findInt32("generation", &generation));
594 return generation != mBufferGeneration;
595}
596
597status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
598 sp<ABuffer> accessUnit;
599 bool dropAccessUnit;
600 do {
601 status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
602
603 if (err == -EWOULDBLOCK) {
604 return err;
605 } else if (err != OK) {
606 if (err == INFO_DISCONTINUITY) {
607 int32_t type;
608 CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
609
610 bool formatChange =
611 (mIsAudio &&
612 (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
613 || (!mIsAudio &&
614 (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
615
616 bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
617
618 ALOGI("%s discontinuity (format=%d, time=%d)",
619 mIsAudio ? "audio" : "video", formatChange, timeChange);
620
621 bool seamlessFormatChange = false;
622 sp<AMessage> newFormat = mSource->getFormat(mIsAudio);
623 if (formatChange) {
624 seamlessFormatChange =
625 supportsSeamlessFormatChange(newFormat);
626 // treat seamless format change separately
627 formatChange = !seamlessFormatChange;
628 }
629
Chong Zhang66704af2015-03-03 19:32:35 -0800630 // For format or time change, return EOS to queue EOS input,
631 // then wait for EOS on output.
Chong Zhang7137ec72014-11-12 16:41:05 -0800632 if (formatChange /* not seamless */) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800633 mFormatChangePending = true;
Chong Zhang66704af2015-03-03 19:32:35 -0800634 err = ERROR_END_OF_STREAM;
Chong Zhang7137ec72014-11-12 16:41:05 -0800635 } else if (timeChange) {
Chong Zhang7137ec72014-11-12 16:41:05 -0800636 rememberCodecSpecificData(newFormat);
Chong Zhang66704af2015-03-03 19:32:35 -0800637 mTimeChangePending = true;
638 err = ERROR_END_OF_STREAM;
Chong Zhang7137ec72014-11-12 16:41:05 -0800639 } else if (seamlessFormatChange) {
640 // reuse existing decoder and don't flush
641 rememberCodecSpecificData(newFormat);
Chong Zhang66704af2015-03-03 19:32:35 -0800642 continue;
Chong Zhang7137ec72014-11-12 16:41:05 -0800643 } else {
644 // This stream is unaffected by the discontinuity
645 return -EWOULDBLOCK;
646 }
647 }
648
Chong Zhang66704af2015-03-03 19:32:35 -0800649 // reply should only be returned without a buffer set
650 // when there is an error (including EOS)
651 CHECK(err != OK);
652
Chong Zhang7137ec72014-11-12 16:41:05 -0800653 reply->setInt32("err", err);
Chong Zhang66704af2015-03-03 19:32:35 -0800654 return ERROR_END_OF_STREAM;
Chong Zhang7137ec72014-11-12 16:41:05 -0800655 }
656
657 if (!mIsAudio) {
658 ++mNumFramesTotal;
659 }
660
661 dropAccessUnit = false;
662 if (!mIsAudio
663 && !mIsSecure
664 && mRenderer->getVideoLateByUs() > 100000ll
665 && mIsVideoAVC
666 && !IsAVCReferenceFrame(accessUnit)) {
667 dropAccessUnit = true;
668 ++mNumFramesDropped;
669 }
670 } while (dropAccessUnit);
671
672 // ALOGV("returned a valid buffer of %s data", mIsAudio ? "mIsAudio" : "video");
673#if 0
674 int64_t mediaTimeUs;
675 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
Chong Zhang5abbd3d2015-04-20 16:03:00 -0700676 ALOGV("[%s] feeding input buffer at media time %.3f",
Chong Zhang7137ec72014-11-12 16:41:05 -0800677 mIsAudio ? "audio" : "video",
678 mediaTimeUs / 1E6);
679#endif
680
681 if (mCCDecoder != NULL) {
682 mCCDecoder->decode(accessUnit);
683 }
684
685 reply->setBuffer("buffer", accessUnit);
686
687 return OK;
688}
689
690bool NuPlayer::Decoder::onInputBufferFetched(const sp<AMessage> &msg) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800691 size_t bufferIx;
692 CHECK(msg->findSize("buffer-ix", &bufferIx));
693 CHECK_LT(bufferIx, mInputBuffers.size());
694 sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
695
696 sp<ABuffer> buffer;
697 bool hasBuffer = msg->findBuffer("buffer", &buffer);
Lajos Molnar09524832014-07-17 14:29:51 -0700698
699 // handle widevine classic source - that fills an arbitrary input buffer
700 MediaBuffer *mediaBuffer = NULL;
Wei Jia96e92b52014-09-18 17:36:20 -0700701 if (hasBuffer) {
702 mediaBuffer = (MediaBuffer *)(buffer->getMediaBufferBase());
703 if (mediaBuffer != NULL) {
Lajos Molnar09524832014-07-17 14:29:51 -0700704 // likely filled another buffer than we requested: adjust buffer index
705 size_t ix;
706 for (ix = 0; ix < mInputBuffers.size(); ix++) {
707 const sp<ABuffer> &buf = mInputBuffers[ix];
708 if (buf->data() == mediaBuffer->data()) {
709 // all input buffers are dequeued on start, hence the check
Wei Jia2245fc62014-10-02 15:12:25 -0700710 if (!mInputBufferIsDequeued[ix]) {
711 ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
712 mComponentName.c_str(), ix, bufferIx);
713 mediaBuffer->release();
714 return false;
715 }
Lajos Molnar09524832014-07-17 14:29:51 -0700716
717 // TRICKY: need buffer for the metadata, so instead, set
718 // codecBuffer to the same (though incorrect) buffer to
719 // avoid a memcpy into the codecBuffer
720 codecBuffer = buffer;
721 codecBuffer->setRange(
722 mediaBuffer->range_offset(),
723 mediaBuffer->range_length());
724 bufferIx = ix;
725 break;
726 }
727 }
728 CHECK(ix < mInputBuffers.size());
729 }
730 }
731
Lajos Molnar1cd13982014-01-17 15:12:51 -0800732 if (buffer == NULL /* includes !hasBuffer */) {
733 int32_t streamErr = ERROR_END_OF_STREAM;
734 CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
735
Chong Zhang66704af2015-03-03 19:32:35 -0800736 CHECK(streamErr != OK);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800737
738 // attempt to queue EOS
739 status_t err = mCodec->queueInputBuffer(
740 bufferIx,
741 0,
742 0,
743 0,
744 MediaCodec::BUFFER_FLAG_EOS);
Andy Hungcf31f1e2014-09-23 14:59:01 -0700745 if (err == OK) {
746 mInputBufferIsDequeued.editItemAt(bufferIx) = false;
747 } else if (streamErr == ERROR_END_OF_STREAM) {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800748 streamErr = err;
749 // err will not be ERROR_END_OF_STREAM
750 }
751
752 if (streamErr != ERROR_END_OF_STREAM) {
Andy Hungcf31f1e2014-09-23 14:59:01 -0700753 ALOGE("Stream error for %s (err=%d), EOS %s queued",
754 mComponentName.c_str(),
755 streamErr,
756 err == OK ? "successfully" : "unsuccessfully");
Lajos Molnar1cd13982014-01-17 15:12:51 -0800757 handleError(streamErr);
758 }
759 } else {
Wei Jiac6cfd702014-11-11 16:33:20 -0800760 sp<AMessage> extra;
761 if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
762 int64_t resumeAtMediaTimeUs;
763 if (extra->findInt64(
764 "resume-at-mediaTimeUs", &resumeAtMediaTimeUs)) {
765 ALOGI("[%s] suppressing rendering until %lld us",
766 mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
767 mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
768 }
769 }
770
Lajos Molnar1cd13982014-01-17 15:12:51 -0800771 int64_t timeUs = 0;
772 uint32_t flags = 0;
773 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
774
Lajos Molnar87603c02014-08-20 19:25:30 -0700775 int32_t eos, csd;
776 // we do not expect SYNCFRAME for decoder
Lajos Molnar1cd13982014-01-17 15:12:51 -0800777 if (buffer->meta()->findInt32("eos", &eos) && eos) {
778 flags |= MediaCodec::BUFFER_FLAG_EOS;
Lajos Molnar87603c02014-08-20 19:25:30 -0700779 } else if (buffer->meta()->findInt32("csd", &csd) && csd) {
780 flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800781 }
782
783 // copy into codec buffer
784 if (buffer != codecBuffer) {
785 CHECK_LE(buffer->size(), codecBuffer->capacity());
786 codecBuffer->setRange(0, buffer->size());
787 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
788 }
789
790 status_t err = mCodec->queueInputBuffer(
791 bufferIx,
792 codecBuffer->offset(),
793 codecBuffer->size(),
794 timeUs,
795 flags);
796 if (err != OK) {
Andy Hungcf31f1e2014-09-23 14:59:01 -0700797 if (mediaBuffer != NULL) {
798 mediaBuffer->release();
799 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800800 ALOGE("Failed to queue input buffer for %s (err=%d)",
801 mComponentName.c_str(), err);
802 handleError(err);
Andy Hungcf31f1e2014-09-23 14:59:01 -0700803 } else {
804 mInputBufferIsDequeued.editItemAt(bufferIx) = false;
805 if (mediaBuffer != NULL) {
806 CHECK(mMediaBuffers[bufferIx] == NULL);
807 mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
808 }
Lajos Molnar09524832014-07-17 14:29:51 -0700809 }
Lajos Molnar1cd13982014-01-17 15:12:51 -0800810 }
Wei Jia2245fc62014-10-02 15:12:25 -0700811 return true;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800812}
813
Lajos Molnar1cd13982014-01-17 15:12:51 -0800814void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
815 status_t err;
816 int32_t render;
817 size_t bufferIx;
Chong Zhang66704af2015-03-03 19:32:35 -0800818 int32_t eos;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800819 CHECK(msg->findSize("buffer-ix", &bufferIx));
Wei Jiac6cfd702014-11-11 16:33:20 -0800820
Chong Zhang7137ec72014-11-12 16:41:05 -0800821 if (!mIsAudio) {
Wei Jiac6cfd702014-11-11 16:33:20 -0800822 int64_t timeUs;
823 sp<ABuffer> buffer = mOutputBuffers[bufferIx];
824 buffer->meta()->findInt64("timeUs", &timeUs);
Chong Zhang7137ec72014-11-12 16:41:05 -0800825
826 if (mCCDecoder != NULL && mCCDecoder->isSelected()) {
827 mCCDecoder->display(timeUs);
828 }
Wei Jiac6cfd702014-11-11 16:33:20 -0800829 }
830
Lajos Molnar1cd13982014-01-17 15:12:51 -0800831 if (msg->findInt32("render", &render) && render) {
Lajos Molnardc43dfa2014-05-07 15:33:04 -0700832 int64_t timestampNs;
833 CHECK(msg->findInt64("timestampNs", &timestampNs));
834 err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);
Lajos Molnar1cd13982014-01-17 15:12:51 -0800835 } else {
836 err = mCodec->releaseOutputBuffer(bufferIx);
837 }
838 if (err != OK) {
839 ALOGE("failed to release output buffer for %s (err=%d)",
840 mComponentName.c_str(), err);
841 handleError(err);
842 }
Chong Zhang66704af2015-03-03 19:32:35 -0800843 if (msg->findInt32("eos", &eos) && eos
844 && isDiscontinuityPending()) {
845 finishHandleDiscontinuity(true /* flushOnTimeChange */);
846 }
847}
848
849bool NuPlayer::Decoder::isDiscontinuityPending() const {
850 return mFormatChangePending || mTimeChangePending;
851}
852
853void NuPlayer::Decoder::finishHandleDiscontinuity(bool flushOnTimeChange) {
854 ALOGV("finishHandleDiscontinuity: format %d, time %d, flush %d",
855 mFormatChangePending, mTimeChangePending, flushOnTimeChange);
856
857 // If we have format change, pause and wait to be killed;
858 // If we have time change only, flush and restart fetching.
859
860 if (mFormatChangePending) {
861 mPaused = true;
862 } else if (mTimeChangePending) {
863 if (flushOnTimeChange) {
Marco Nelissen421f47c2015-03-25 14:40:32 -0700864 doFlush(false /* notifyComplete */);
865 signalResume(false /* notifyComplete */);
Chong Zhang66704af2015-03-03 19:32:35 -0800866 }
Chong Zhang66704af2015-03-03 19:32:35 -0800867 }
868
869 // Notify NuPlayer to either shutdown decoder, or rescan sources
870 sp<AMessage> msg = mNotify->dup();
871 msg->setInt32("what", kWhatInputDiscontinuity);
872 msg->setInt32("formatChange", mFormatChangePending);
873 msg->post();
874
875 mFormatChangePending = false;
876 mTimeChangePending = false;
Lajos Molnar1cd13982014-01-17 15:12:51 -0800877}
878
Chong Zhang7137ec72014-11-12 16:41:05 -0800879bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(
880 const sp<AMessage> &targetFormat) const {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800881 if (targetFormat == NULL) {
882 return true;
883 }
884
885 AString mime;
886 if (!targetFormat->findString("mime", &mime)) {
887 return false;
888 }
889
890 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
891 // field-by-field comparison
892 const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
893 for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
894 int32_t oldVal, newVal;
joakim johansson7abbd4c2015-01-30 14:16:03 +0100895 if (!mInputFormat->findInt32(keys[i], &oldVal) ||
Lajos Molnar1cd13982014-01-17 15:12:51 -0800896 !targetFormat->findInt32(keys[i], &newVal) ||
897 oldVal != newVal) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800898 return false;
899 }
900 }
901
902 sp<ABuffer> oldBuf, newBuf;
joakim johansson7abbd4c2015-01-30 14:16:03 +0100903 if (mInputFormat->findBuffer("csd-0", &oldBuf) &&
Lajos Molnar1cd13982014-01-17 15:12:51 -0800904 targetFormat->findBuffer("csd-0", &newBuf)) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800905 if (oldBuf->size() != newBuf->size()) {
906 return false;
907 }
908 return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size());
909 }
910 }
911 return false;
912}
913
914bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
joakim johansson7abbd4c2015-01-30 14:16:03 +0100915 if (mInputFormat == NULL) {
Robert Shih6d0a94e2014-01-23 16:18:22 -0800916 return false;
917 }
918
919 if (targetFormat == NULL) {
920 return true;
921 }
922
923 AString oldMime, newMime;
joakim johansson7abbd4c2015-01-30 14:16:03 +0100924 if (!mInputFormat->findString("mime", &oldMime)
Robert Shih6d0a94e2014-01-23 16:18:22 -0800925 || !targetFormat->findString("mime", &newMime)
926 || !(oldMime == newMime)) {
927 return false;
928 }
929
930 bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
931 bool seamless;
932 if (audio) {
933 seamless = supportsSeamlessAudioFormatChange(targetFormat);
934 } else {
Lajos Molnar1cd13982014-01-17 15:12:51 -0800935 int32_t isAdaptive;
936 seamless = (mCodec != NULL &&
937 mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
938 isAdaptive);
Robert Shih6d0a94e2014-01-23 16:18:22 -0800939 }
940
941 ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
942 return seamless;
943}
944
Chong Zhang7137ec72014-11-12 16:41:05 -0800945void NuPlayer::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) {
946 if (format == NULL) {
Chong Zhangb86e68f2014-08-01 13:46:53 -0700947 return;
948 }
Chong Zhang7137ec72014-11-12 16:41:05 -0800949 mCSDsForCurrentFormat.clear();
950 for (int32_t i = 0; ; ++i) {
951 AString tag = "csd-";
952 tag.append(i);
953 sp<ABuffer> buffer;
954 if (!format->findBuffer(tag.c_str(), &buffer)) {
955 break;
956 }
957 mCSDsForCurrentFormat.push(buffer);
Chong Zhanga7fa1d92014-06-11 14:49:23 -0700958 }
Chong Zhangb86e68f2014-08-01 13:46:53 -0700959}
960
Chong Zhangf8d71772014-11-26 15:08:34 -0800961void NuPlayer::Decoder::notifyResumeCompleteIfNecessary() {
962 if (mResumePending) {
963 mResumePending = false;
964
965 sp<AMessage> notify = mNotify->dup();
966 notify->setInt32("what", kWhatResumeCompleted);
967 notify->post();
968 }
969}
970
Andreas Huberf9334412010-12-15 15:17:42 -0800971} // namespace android
972