status_t Converter::doMoreWork() { status_t err; if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { for (;;) { size_t bufferIndex; err = mEncoder->dequeueInputBuffer(&bufferIndex); if (err != OK) { break; } mAvailEncoderInputIndices.push_back(bufferIndex); } feedEncoderInputBuffers(); } for (;;) { size_t bufferIndex; size_t offset; size_t size; int64_t timeUs; uint32_t flags; native_handle_t* handle = NULL; err = mEncoder->dequeueOutputBuffer( &bufferIndex, &offset, &size, &timeUs, &flags); if (err != OK) { if (err == INFO_FORMAT_CHANGED) { continue; } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { mEncoder->getOutputBuffers(&mEncoderOutputBuffers); continue; } if (err == -EAGAIN) { err = OK; } break; } if (flags & MediaCodec::BUFFER_FLAG_EOS) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatEOS); notify->post(); } else { #if 0 if (mIsVideo) { int32_t videoBitrate = GetInt32Property( "media.wfd.video-bitrate", 5000000); setVideoBitrate(videoBitrate); } #endif sp<ABuffer> buffer; sp<ABuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex); if (outbuf->meta()->findPointer("handle", (void**)&handle) && handle != NULL) { int32_t rangeLength, rangeOffset; CHECK(outbuf->meta()->findInt32("rangeOffset", &rangeOffset)); CHECK(outbuf->meta()->findInt32("rangeLength", &rangeLength)); outbuf->meta()->setPointer("handle", NULL); // MediaSender will post the following message when HDCP // is done, to release the output buffer back to encoder. sp<AMessage> notify(new AMessage(kWhatReleaseOutputBuffer, this)); notify->setInt32("bufferIndex", bufferIndex); buffer = new ABuffer( rangeLength > (int32_t)size ? rangeLength : size); buffer->meta()->setPointer("handle", handle); buffer->meta()->setInt32("rangeOffset", rangeOffset); buffer->meta()->setInt32("rangeLength", rangeLength); buffer->meta()->setMessage("notify", notify); } else { buffer = new ABuffer(size); } buffer->meta()->setInt64("timeUs", timeUs); ALOGV("[%s] time %lld us (%.2f secs)", mIsVideo ? "video" : "audio", (long long)timeUs, timeUs / 1E6); memcpy(buffer->data(), outbuf->base() + offset, size); if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { if (!handle) { if (mIsH264) { mCSD0 = buffer; } mOutputFormat->setBuffer("csd-0", buffer); } } else { if (mNeedToManuallyPrependSPSPPS && mIsH264 && (mFlags & FLAG_PREPEND_CSD_IF_NECESSARY) && IsIDR(buffer)) { buffer = prependCSD(buffer); } sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatAccessUnit); notify->setBuffer("accessUnit", buffer); notify->post(); } } if (!handle) { mEncoder->releaseOutputBuffer(bufferIndex); } if (flags & MediaCodec::BUFFER_FLAG_EOS) { break; } } return err; }
status_t Converter::doMoreWork() { status_t err; for (;;) { size_t bufferIndex; err = mEncoder->dequeueInputBuffer(&bufferIndex); if (err != OK) { break; } mAvailEncoderInputIndices.push_back(bufferIndex); } feedEncoderInputBuffers(); for (;;) { size_t bufferIndex; size_t offset; size_t size; int64_t timeUs; uint32_t flags; err = mEncoder->dequeueOutputBuffer( &bufferIndex, &offset, &size, &timeUs, &flags); if (err != OK) { if (err == -EAGAIN) { err = OK; } break; } if (flags & MediaCodec::BUFFER_FLAG_EOS) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatEOS); notify->post(); } else { sp<ABuffer> buffer = new ABuffer(size); buffer->meta()->setInt64("timeUs", timeUs); ALOGV("[%s] time %lld us (%.2f secs)", mIsVideo ? "video" : "audio", timeUs, timeUs / 1E6); memcpy(buffer->data(), mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset, size); if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { mOutputFormat->setBuffer("csd-0", buffer); } else { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatAccessUnit); notify->setBuffer("accessUnit", buffer); notify->post(); } } mEncoder->releaseOutputBuffer(bufferIndex); if (flags & MediaCodec::BUFFER_FLAG_EOS) { break; } } return err; }
void Converter::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatMediaPullerNotify: { int32_t what; CHECK(msg->findInt32("what", &what)); if (!mIsPCMAudio && mEncoder == NULL) { ALOGV("got msg '%s' after encoder shutdown.", msg->debugString().c_str()); if (what == MediaPuller::kWhatAccessUnit) { sp<ABuffer> accessUnit; CHECK(msg->findBuffer("accessUnit", &accessUnit)); accessUnit->setMediaBufferBase(NULL); } break; } if (what == MediaPuller::kWhatEOS) { mInputBufferQueue.push_back(NULL); feedEncoderInputBuffers(); scheduleDoMoreWork(); } else { CHECK_EQ(what, MediaPuller::kWhatAccessUnit); sp<ABuffer> accessUnit; CHECK(msg->findBuffer("accessUnit", &accessUnit)); if (mNumFramesToDrop > 0 || mEncodingSuspended) { if (mNumFramesToDrop > 0) { --mNumFramesToDrop; ALOGI("dropping frame."); } accessUnit->setMediaBufferBase(NULL); break; } #if 0 MediaBuffer *mbuf = (MediaBuffer *)(accessUnit->getMediaBufferBase()); if (mbuf != NULL) { ALOGI("queueing mbuf %p", mbuf); mbuf->release(); } #endif #if ENABLE_SILENCE_DETECTION if (!mIsVideo) { if (IsSilence(accessUnit)) { if (mInSilentMode) { break; } int64_t nowUs = ALooper::GetNowUs(); if (mFirstSilentFrameUs < 0ll) { mFirstSilentFrameUs = nowUs; } else if (nowUs >= mFirstSilentFrameUs + 10000000ll) { mInSilentMode = true; ALOGI("audio in silent mode now."); break; } } else { if (mInSilentMode) { ALOGI("audio no longer in silent mode."); } mInSilentMode = false; mFirstSilentFrameUs = -1ll; } } #endif mInputBufferQueue.push_back(accessUnit); feedEncoderInputBuffers(); scheduleDoMoreWork(); } break; } case kWhatEncoderActivity: { #if 0 int64_t whenUs; if (msg->findInt64("whenUs", &whenUs)) { int64_t nowUs = ALooper::GetNowUs(); ALOGI("[%s] kWhatEncoderActivity after %lld us", mIsVideo ? "video" : "audio", nowUs - whenUs); } #endif mDoMoreWorkPending = false; if (mEncoder == NULL) { break; } status_t err = doMoreWork(); if (err != OK) { notifyError(err); } else { scheduleDoMoreWork(); } break; } case kWhatRequestIDRFrame: { if (mEncoder == NULL) { break; } if (mIsVideo) { ALOGV("requesting IDR frame"); mEncoder->requestIDRFrame(); } break; } case kWhatShutdown: { ALOGI("shutting down %s encoder", mIsVideo ? "video" : "audio"); releaseEncoder(); AString mime; CHECK(mOutputFormat->findString("mime", &mime)); ALOGI("encoder (%s) shut down.", mime.c_str()); sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatShutdownCompleted); notify->post(); break; } case kWhatDropAFrame: { ++mNumFramesToDrop; break; } case kWhatReleaseOutputBuffer: { if (mEncoder != NULL) { size_t bufferIndex; CHECK(msg->findInt32("bufferIndex", (int32_t*)&bufferIndex)); CHECK(bufferIndex < mEncoderOutputBuffers.size()); mEncoder->releaseOutputBuffer(bufferIndex); } break; } case kWhatSuspendEncoding: { int32_t suspend; CHECK(msg->findInt32("suspend", &suspend)); mEncodingSuspended = suspend; if (mFlags & FLAG_USE_SURFACE_INPUT) { sp<AMessage> params = new AMessage; params->setInt32("drop-input-frames",suspend); mEncoder->setParameters(params); } break; } default: TRESPASS(); } }
void Converter::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatMediaPullerNotify: { int32_t what; CHECK(msg->findInt32("what", &what)); if (!mIsPCMAudio && mEncoder == NULL) { ALOGV("got msg '%s' after encoder shutdown.", msg->debugString().c_str()); if (what == MediaPuller::kWhatAccessUnit) { sp<ABuffer> accessUnit; CHECK(msg->findBuffer("accessUnit", &accessUnit)); void *mbuf; if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) && mbuf != NULL) { ALOGV("releasing mbuf %p", mbuf); accessUnit->meta()->setPointer("mediaBuffer", NULL); static_cast<MediaBuffer *>(mbuf)->release(); mbuf = NULL; } } break; } if (what == MediaPuller::kWhatEOS) { mInputBufferQueue.push_back(NULL); feedEncoderInputBuffers(); scheduleDoMoreWork(); } else { CHECK_EQ(what, MediaPuller::kWhatAccessUnit); sp<ABuffer> accessUnit; CHECK(msg->findBuffer("accessUnit", &accessUnit)); #if 0 void *mbuf; if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) && mbuf != NULL) { ALOGI("queueing mbuf %p", mbuf); } #endif #if ENABLE_SILENCE_DETECTION if (!mIsVideo) { if (IsSilence(accessUnit)) { if (mInSilentMode) { break; } int64_t nowUs = ALooper::GetNowUs(); if (mFirstSilentFrameUs < 0ll) { mFirstSilentFrameUs = nowUs; } else if (nowUs >= mFirstSilentFrameUs + 10000000ll) { mInSilentMode = true; ALOGI("audio in silent mode now."); break; } } else { if (mInSilentMode) { ALOGI("audio no longer in silent mode."); } mInSilentMode = false; mFirstSilentFrameUs = -1ll; } } #endif mInputBufferQueue.push_back(accessUnit); feedEncoderInputBuffers(); scheduleDoMoreWork(); } break; } case kWhatEncoderActivity: { #if 0 int64_t whenUs; if (msg->findInt64("whenUs", &whenUs)) { int64_t nowUs = ALooper::GetNowUs(); ALOGI("[%s] kWhatEncoderActivity after %lld us", mIsVideo ? "video" : "audio", nowUs - whenUs); } #endif mDoMoreWorkPending = false; if (mEncoder == NULL) { break; } status_t err = doMoreWork(); if (err != OK) { notifyError(err); } else { scheduleDoMoreWork(); } break; } case kWhatRequestIDRFrame: { if (mEncoder == NULL) { break; } if (mIsVideo) { ALOGI("requesting IDR frame"); mEncoder->requestIDRFrame(); } break; } case kWhatShutdown: { ALOGI("shutting down encoder"); /*bugfix: release queue buffer,it may fall into blackhold. * when 4kplayer is floating in the dynamic desktop, * and someone disable wifi in the quicksetting, this will lead to UI deadlock. * It mainly let the source emit onDisplayDisconnect msg to framework. */ while (!mInputBufferQueue.empty()) { sp<ABuffer> accessUnit = *mInputBufferQueue.begin(); mInputBufferQueue.erase(mInputBufferQueue.begin()); void *mbuf = NULL; if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) && mbuf != NULL) { ALOGI(">>releasing mbuf %p", mbuf); accessUnit->meta()->setPointer("mediaBuffer", NULL); static_cast<MediaBuffer *>(mbuf)->release(); mbuf = NULL; } } if (mEncoder != NULL) { mEncoder->release(); mEncoder.clear(); } AString mime; CHECK(mInputFormat->findString("mime", &mime)); ALOGI("encoder (%s) shut down.", mime.c_str()); break; } default: TRESPASS(); } }