巩义网站推广客户关系管理定义

当前位置: 首页 > news >正文

巩义网站推广,客户关系管理定义,网站建设都是需要什么,精致的个人网站Android音视频 MediaCodec框架-启动编码 简述 上一节我们介绍了MediaCodec框架创建编码器流程#xff0c;编解码的流程其实基本是一样的#xff0c;只是底层的最终的实现组件不同#xff0c;所以我们只看启动编码流程。 MediaCodec启动编码 从MediaCodec的start方法开始…Android音视频 MediaCodec框架-启动编码 简述 上一节我们介绍了MediaCodec框架创建编码器流程编解码的流程其实基本是一样的只是底层的最终的实现组件不同所以我们只看启动编码流程。 MediaCodec启动编码 从MediaCodec的start方法开始。
1.1 MediaCodec.start 调用jni方法native_start public final void start() {native_start(); }1.2 native_start 调用JMediaCodec的start方法。 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {ALOGV(android_media_MediaCodec_start);spJMediaCodec codec getMediaCodec(env, thiz);// … JMediaCodec状态检测// 详见1.3status_t err codec-start();// … }1.3 JMediaCodec::start 调用MediaCodec的start方法。 status_t JMediaCodec::start() {// 详见1.4return mCodec-start(); }1.4 MediaCodec::start 发送kWhatStart的AMessage通知CCodec2 start这个流程和init很类似处理消息start的流程详见1.5 status_t MediaCodec::start() {spAMessage msg new AMessage(kWhatStart, this);spAMessage callback;status_t err;std::vectorMediaResourceParcel resources;resources.push_back(MediaResource::CodecResource(mFlags kFlagIsSecure,toMediaResourceSubType(mDomain)));resources.push_back(MediaResource::GraphicMemoryResource(1));for (int i 0; i kMaxRetry; i) {if (i 0) {// …spAMessage response;err PostAndAwaitResponse(mConfigureMsg, response);// …}// …}return err; }1.5 MediaCodec::onMessageReceived 消息处理方法调用CCodec的initiateStart void MediaCodec::onMessageReceived(const spAMessage msg) {// …case kWhatStart:{// …// 更新状态到STARTINGsetState(STARTING);// 调用CCodec的initiateStart详见1.6mCodec-initiateStart();break;}// … }1.6 CCodec::initiateStart 这里只是修改了状态到STARTING然后做了消息转发。 void CCodec::initiateStart() {auto setStarting [this] {MutexedState::Locked state(mState);if (state-get() ! ALLOCATED) {return UNKNOWN_ERROR;}state-set(STARTING);return OK;};if (tryAndReportOnError(setStarting) ! OK) {return;}(new AMessage(kWhatStart, this))-post(); }1.7 CCodec::onMessageReceived 调用CCodec::start方法。 void CCodec::onMessageReceived(const spAMessage msg) {// …case kWhatStart: {// 调用start方法setDeadline(now, 1500ms, start);start();break;}// … }1.8 CCodec::start 该方法主要做了几件事 调用Component的start方法Codec2的Component都是基于SimpleC2Component实现的SimpleC2Component中处理了一些状态管理的逻辑不同的编解码组件继承了SimpleC2Component实现生命周期回调方法例如onInit等。 从CCodecConfig获取mOutputFormat或者inputFormat信息前者是解码时会有后者是编码才会有的。 调用CCodecBufferChannel::start。 void CCodec::start() {// …// 调用Component start,Codec2的Component都是基于SimpleC2Component实现的SimpleC2Component中处理了一些状态管理的逻辑// 不同的编解码最终实现都继承于SimpleC2Component然后实现对应的生命周期回调方法做自己的事由于我们H264的实现里没有做什么事就不看了。c2_status_t err comp-start();if (err ! C2_OK) {mCallback-onError(toStatusT(err, C2_OPERATION_Component_start),ACTION_CODE_FATAL);return;}spAMessage inputFormat;spAMessage outputFormat;status_t err2 OK;bool buffersBoundToCodec false;{// CCodecConfig是在之前初始化的里面有配置信息这里mOutputFormat是解码时候才有的而inputFormat则是编码的时候才有// mInputSurface是编码时候配置了InputSurface时传入的参数表示编码数据来源于一个Surface// 我们之前在SurfaceFlinger章节说过Surface是表示一个窗口可以作为图像BufferQueue的一个生产者。Mutexedstd::unique_ptrConfig::Locked configLocked(mConfig);const std::unique_ptrConfig config *configLocked;inputFormat config-mInputFormat;outputFormat config-mOutputFormat config-mOutputFormat-dup();if (config-mInputSurface) {err2 config-mInputSurface-start();config-mInputSurfaceDataspace config-mInputSurface-getDataspace();}buffersBoundToCodec config-mBuffersBoundToCodec;}if (err2 ! OK) {mCallback-onError(err2, ACTION_CODE_FATAL);return;}// 调用CCodecBufferChannel::start,详见1.9err2 mChannel-start(inputFormat, outputFormat, buffersBoundToCodec);if (err2 ! OK) {mCallback-onError(err2, ACTION_CODE_FATAL);return;}// … 更新状态std::mapsize_t, spMediaCodecBuffer clientInputBuffers;// 根据input里numSlots数量调用input-buffers-requestNewBuffer创建buffer填充clientInputBuffers。err2 mChannel-prepareInitialInputBuffers(clientInputBuffers);if (err2 ! OK) {ALOGE(Initial preparation for Input Buffers failed);mCallback-onError(err2, ACTION_CODE_FATAL);return;}// 回调MediaCodec onStartCompletedmCallback-onStartCompleted();mChannel-requestInitialInputBuffers(std::move(clientInputBuffers)); }1.9 CCodecBufferChannel::start 这个方法很长主要是一些参数的初始化分为编码和解码的情况其中最重要的参数就是C2BlockPool和input/output。 以编码为例input里面有一个buffers这个buffers有多种类型buffers会持有一个C2BlockPool来分配内存而C2BlockPool又会通过Allocator分配C2Buffer这里的Allocator也是在hal层Allocator是通过AllocatorStore到hal获取到。 所以相当于在上层使用一个buffers来控制buffer到分配释放等这个buffers类型比如LinearInputBuffersGraphicInputBuffersGraphicMetadataInputBuffers等而buffers会通过C2BlockPool分配buffer而C2BlockPool会通过Allocator到hal层获取buffer。 解码的情况类似这里就不细说了。 status_t CCodecBufferChannel::start(const spAMessage inputFormat,const spAMessage outputFormat,bool buffersBoundToCodec) {C2StreamBufferTypeSetting::input iStreamFormat(0u);C2StreamBufferTypeSetting::output oStreamFormat(0u);C2ComponentKindSetting kind;C2PortReorderBufferDepthTuning::output reorderDepth;C2PortReorderKeySetting::output reorderKey;C2PortActualDelayTuning::input inputDelay(0);C2PortActualDelayTuning::output outputDelay(0);C2ActualPipelineDelayTuning pipelineDelay(0);C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);// … 参数初始化以及检测// 由C2AllocateStore来获取Allocation而Allocation是用于分配buffer的有不同类型的buffer对应底层分配的内存可能也不同例如dmastd::shared_ptrC2AllocatorStore allocatorStore GetCodec2PlatformAllocatorStore();int poolMask GetCodec2PoolMask();C2PlatformAllocatorStore::id_t preferredLinearId GetPreferredLinearAllocatorId(poolMask);// 编码if (inputFormat ! nullptr) {// … 参数配置// 构造C2BlockPoolstd::shared_ptrC2BlockPool pool;{MutexedBlockPools::Locked pools(mBlockPools);// … 参数检查配置if ((poolMask pools-inputAllocatorId) 1) {// 根据inputAllocatorId构造C2BlockPoolC2BlockPool里面持有Allocator通过擦欧总Allocator管理Buffer的构建err CreateCodec2BlockPool(pools-inputAllocatorId, nullptr, pool);// …} else {err C2_NOT_FOUND;}// …异常处理pools-inputPool pool;}bool forceArrayMode false;MutexedInput::Locked input(mInput);// …构造填充input对象// 其中input-buffers会根据buffer的类型不同而不同// 这里的关系是input-buffers会最终提供给CCodec分配Buffer的能力而input-buffers是通过前面构造的C2BlockPool来获取或者释放buffer// 而C2BlockPool通过持有的Allocator来分配不同Buffer不同的Buffer的区别在于底层可能使用不同的系统调用来分配内存可能是dma之类的。input-buffers-setFormat(inputFormat);if (err C2_OK) {input-buffers-setPool(pool);} else {// TODO: error}if (forceArrayMode) {input-buffers input-buffers-toArrayMode(numInputSlots);}}// 解码这里和上面编码类似主要是初始化一些必要对象。if (outputFormat ! nullptr) {spIGraphicBufferProducer outputSurface;uint32_t outputGeneration;int maxDequeueCount 0;{MutexedOutputSurface::Locked output(mOutputSurface);maxDequeueCount output-maxDequeueBuffers numOutputSlots reorderDepth.value mRenderingDepth;outputSurface output-surface ?output-surface-getIGraphicBufferProducer() : nullptr;if (outputSurface) {output-surface-setMaxDequeuedBufferCount(output-maxDequeueBuffers);}outputGeneration output-generation;}bool graphic (oStreamFormat.value C2BufferData::GRAPHIC);C2BlockPool::local_idt outputPoolId;C2BlockPool::local_idt prevOutputPoolId;{MutexedBlockPools::Locked pools(mBlockPools);// … 初始化BlockPools和解码流程构造C2BlockPools类似。}MutexedOutput::Locked output(mOutput);// … 构造output和上面input类似// 如果接受输出是一个Surface通知给Componentif (outputSurface) {mComponent-setOutputSurface(outputPoolId,outputSurface,outputGeneration,maxDequeueCount);} else {// …}// …}// 编解码监测器初始化if (inputFormat || outputFormat) {MutexedPipelineWatcher::Locked watcher(mPipelineWatcher);watcher-inputDelay(inputDelayValue).pipelineDelay(pipelineDelayValue).outputDelay(outputDelayValue).smoothnessFactor(kSmoothnessFactor);watcher-flush();}mInputMetEos false;// 初始化buffer的锁mSync.start();return OK; }MediaCodec 获取buffer index 在创建并启动解码器后我们会通过dequeueInputBuffer获取一个Buffer index然后再通过getInputBuffers获取所有Buffer数组然后根据索引在Buffer数组中获取buffer往里面写入需要编码的数据接下来我们来看看这个流程。
2.1 MediaCodec.dequeueInputBuffer jni调用native_dequeueInputBuffer。 public final int dequeueInputBuffer(long timeoutUs) {// …// 详见2.2int res native_dequeueInputBuffer(timeoutUs);// …return res; }2.2 android_media_MediaCodec_dequeueInputBuffer 调用JMediaCodec::dequeueInputBuffer static jint android_media_MediaCodec_dequeueInputBuffer(JNIEnv *env, jobject thiz, jlong timeoutUs) {// …size_t index;// JMediaCodec::dequeueInputBuffer,详见2.3status_t err codec-dequeueInputBuffer(index, timeoutUs);if (err OK) {return (jint) index;}return throwExceptionAsNecessary(env, err, codec); }2.3 JMediaCodec::dequeueInputBuffer C层的MediaCodecMediaCodec::dequeueInputBuffer status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {// 详见2.4return mCodec-dequeueInputBuffer(index, timeoutUs); }2.4 MediaCodec::dequeueInputBuffer 发送kWhatDequeueInputBuffer消息。 status_t MediaCodec::dequeueInputBuffer(size_t index, int64_t timeoutUs) {spAMessage msg new AMessage(kWhatDequeueInputBuffer, this);msg-setInt64(timeoutUs, timeoutUs);spAMessage response;status_t err;// 发送kWhatDequeueInputBuffer消息处理逻辑详见2.5if ((err PostAndAwaitResponse(msg, response)) ! OK) {return err;}CHECK(response-findSize(index, index));return OK; }2.5 MediaCodec::onMessageReceived 调用handleDequeueInputBuffer处理并且发送kWhatDequeueInputTimedOut消息来配置超时监测。 void MediaCodec::onMessageReceived(const spAMessage msg) {switch (msg-what()) {//…case kWhatDequeueInputBuffer:{spAReplyToken replyID;CHECK(msg-senderAwaitsResponse(replyID));// …// 详见2.6if (handleDequeueInputBuffer(replyID, true / new request */)) {break;}// … 通过发送kWhatDequeueInputTimedOut消息配置超时监测break;}// …} }2.6 MediaCodec::handleDequeueInputBuffer 通过dequeuePortBuffer获取buffer index然后返回index。 bool MediaCodec::handleDequeueInputBuffer(const spAReplyToken replyID, bool newRequest) {// …异常处理// 详见2.7ssize_t index dequeuePortBuffer(kPortIndexInput);if (index 0) {CHECK_EQ(index, -EAGAIN);return false;}// 返回indexspAMessage response new AMessage;response-setSize(index, index);response-postReply(replyID);return true; }2.7 MediaCodec::dequeuePortBuffer mAvailPortBuffers里是两个int数组分别给编码和解码使用这里的int数组用于存储可以使用的buffer index。这个方法做的事就是从这个int数组里获取一个index并且将它从数组里移除。 ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {CHECK(portIndex kPortIndexInput || portIndex kPortIndexOutput);BufferInfo *info peekNextPortBuffer(portIndex);if (!info) {return -EAGAIN;}// 从availBuffers获取可用buffer index并且把他从数组中移除。 std::listsize_t *availBuffers mAvailPortBuffers[portIndex];size_t index availBuffers-begin();CHECK_EQ(info, mPortBuffers[portIndex][index]);availBuffers-erase(availBuffers-begin());// …return index; }MediaCodec 获取input buffer数组 3.1 MediaCodec.getInputBuffers public ByteBuffer[] getInputBuffers() {synchronized (mBufferLock) {// …// java层有一个buffer数组缓存第一次需要通过jni去获取详见3.2if (mCachedInputBuffers null) {cacheBuffersLocked(true / input */);}// …return mCachedInputBuffers;} } 3.2 MediaCodec.cacheBuffersLocked 通过jni获取buffers并缓存记录。 private void cacheBuffersLocked(boolean input) {ByteBuffer[] buffers null;try {// 通过jni获取buffer详见3.3buffers getBuffers(input);invalidateByteBuffersLocked(buffers);} catch (IllegalStateException e) {// we dont get buffers in async mode}// …// 缓存记录结果if (input) {mCachedInputBuffers buffers;} else {mCachedOutputBuffers buffers;} }3.3 JMediaCodec::getBuffers jni方法通过调用JMediaCodec的getBuffers而JMediaCodec又通过调用c层的MediaCodec的getInputBuffers来获取buffers。 status_t JMediaCodec::getBuffers(JNIEnv *env, bool input, jobjectArray *bufArray) const {VectorspMediaCodecBuffer buffers;// 详见3.4status_t err input? mCodec-getInputBuffers(buffers): mCodec-getOutputBuffers(buffers);// …将C层的buffers通过jni关联给java层return OK; }3.4 MediaCodec::getInputBuffers 发送kWhatGetBuffers。 status_t MediaCodec::getInputBuffers(VectorspMediaCodecBuffer *buffers) const {spAMessage msg new AMessage(kWhatGetBuffers, this);msg-setInt32(portIndex, kPortIndexInput);msg-setPointer(buffers, buffers);spAMessage response;return PostAndAwaitResponse(msg, response); }3.5 MediaCodec::onMessageReceived 我们目前流程是在获取inputBuffer通过inputBuffer给编码器传入编码前的数据而如果我们配置了InputSurface以InputSurface为输入则不需要获取Buffer。 通过CCodecBufferChannel::getInputBufferArray来获取Buffer数组。 void MediaCodec::onMessageReceived(const spAMessage msg) {// …case kWhatGetBuffers:{// …异常处理dstBuffers-clear();// 通过getInputBufferArray获取buffer如果配置来InputSurface则不会走这个模式。详见3.6if (portIndex ! kPortIndexInput || !mHaveInputSurface) {if (portIndex kPortIndexInput) {mBufferChannel-getInputBufferArray(dstBuffers);} else {mBufferChannel-getOutputBufferArray(dstBuffers);}}mApiUsageMetrics.isArrayMode true;(new AMessage)-postReply(replyID);break;}// … }3.6 CCodecBufferChannel::getInputBufferArray 这里会调用input-buffers-getArray来获取Buffer这里input-buffers是在start的过程中就已经初始化的具体是在1.8节调用mChannel-prepareInitialInputBuffers时候分配的其中会循环调用buffers的requestNewBuffer方法我们之前说过buffers里面有pool而pool会通过allocator来分配buffer。 void CCodecBufferChannel::getInputBufferArray(VectorspMediaCodecBuffer array) {array-clear();MutexedInput::Locked input(mInput);if (!input-buffers) {ALOGE(getInputBufferArray: No Input Buffers allocated);return;}if (!input-buffers-isArrayMode()) {input-buffers input-buffers-toArrayMode(input-numSlots);}input-buffers-getArray(array); }MediacCodec queueInputBuffer 4.1 MediaCodec.queueInputBuffer 调用jni层native_queueInputBuffer public final void queueInputBuffer(int index,int offset, int size, long presentationTimeUs, int flags)throws CryptoException {// …try {// 详见4.2native_queueInputBuffer(index, offset, size, presentationTimeUs, flags);} catch (CryptoException | IllegalStateException e) {revalidateByteBuffer(mCachedInputBuffers, index, true / input */);throw e;} }4.2 android_media_MediaCodec_queueInputBuffer 和之前一样jni会调用JMediaCodec的queueInputBuffer方法。 static void android_media_MediaCodec_queueInputBuffer(JNIEnv *env,jobject thiz,jint index,jint offset,jint size,jlong timestampUs,jint flags) {// …// 详见4.3status_t err codec-queueInputBuffer(index, offset, size, timestampUs, flags, errorDetailMsg);throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL,codec-getExceptionMessage(errorDetailMsg.c_str()).c_str()); }4.3 JMediaCodec::queueInputBuffer 调用MediaCodec的queueInputBuffer status_t JMediaCodec::queueInputBuffer(size_t index,size_t offset, size_t size, int64_t timeUs, uint32_t flags,AString *errorDetailMsg) {//详见4.4return mCodec-queueInputBuffer(index, offset, size, timeUs, flags, errorDetailMsg); }4.4 MediaCodec::queueInputBuffer 发送kWhatQueueInputBuffer消息。 status_t MediaCodec::queueInputBuffer(size_t index,size_t offset,size_t size,int64_t presentationTimeUs,uint32_t flags,AString errorDetailMsg) {if (errorDetailMsg ! NULL) {errorDetailMsg-clear();}spAMessage msg new AMessage(kWhatQueueInputBuffer, this);msg-setSize(index, index);msg-setSize(offset, offset);msg-setSize(size, size);msg-setInt64(timeUs, presentationTimeUs);msg-setInt32(flags, flags);msg-setPointer(errorDetailMsg, errorDetailMsg);spAMessage response;return PostAndAwaitResponse(msg, response); }4.5 MediaCodec::onMessageReceived 调用onQueueInputBuffer处理任务。 void MediaCodec::onMessageReceived(const spAMessage msg) {//…case kWhatQueueInputBuffer:{// …status_t err UNKNOWN_ERROR;if (!mLeftover.empty()) {mLeftover.push_back(msg);size_t index;msg-findSize(index, index);err handleLeftover(index);} else {// 详见4.6err onQueueInputBuffer(msg);}PostReplyWithError(replyID, err);break;}// … }4.6 MediaCodec::onQueueInputBuffer 处理一些参数的检查和传递这里分需要加密和不需要加密的两种场景,我们不看加密的逻辑这里主要构建来一个新的buffer把数据填充并且调用attachBuffer把queue进来的buffer里面的数据拷贝到新建到buffer里。 最后调用queueInputBuffer。 status_t MediaCodec::onQueueInputBuffer(const spAMessage msg) {// … 参数预处理和检查将一些参数配置到buffer// … 加密逻辑if (c2Buffer || memory) {spAMessage tunings NULL;if (msg-findMessage(tunings, tunings) tunings ! NULL) {onSetParameters(tunings);}status_t err OK;if (c2Buffer) {// 拷贝数据到新的buffererr mBufferChannel-attachBuffer(c2Buffer, buffer);} else if (memory) {AString errorDetailMsg;err mBufferChannel-attachEncryptedBuffer(memory, (mFlags kFlagIsSecure), key, iv, mode, pattern,offset, subSamples, numSubSamples, buffer, errorDetailMsg);if (err ! OK hasCryptoOrDescrambler() (mFlags kFlagUseCryptoAsync)) {// … 加密逻辑}} else {// error log}// …}// …if (hasCryptoOrDescrambler() !c2Buffer !memory) {// 需要加密场景} else {// 调用queueInputBuffer详见4.7err mBufferChannel-queueInputBuffer(buffer);// …}// …return err; }4.7 CCodecBufferChannel::queueInputBuffer 调用queueInputBufferInternal。 status_t CCodecBufferChannel::queueInputBuffer(const spMediaCodecBuffer buffer) {QueueGuard guard(mSync);if (!guard.isRunning()) {ALOGD([%s] No more buffers should be queued at current state., mName);return -ENOSYS;}return queueInputBufferInternal(buffer); }4.8 CCodecBufferChannel::queueInputBufferInternal 这里主要会解析buffer然后将buffer里的信息封装到一个C2Work中然后把C2Work存到一个C2Work数组调用Component的queue来处理这个这个任务。 这里Component的queue会在hal层调用到对方的queue_nb方法这里就是SimpleC2Component的::SimpleC2Component。 status_t CCodecBufferChannel::queueInputBufferInternal(spMediaCodecBuffer buffer,std::shared_ptrC2LinearBlock encryptedBlock,size_t blockSize) {// …获取buffer里的参数// …构造一个C2Work数组和一个C2Work后续最终会提交这个数组将信息封装在C2Work中std::liststd::unique_ptrC2Work items;std::unique_ptrC2Work work(new C2Work);work-input.ordinal.timestamp timeUs;work-input.ordinal.frameIndex mFrameIndex;work-input.ordinal.customOrdinal timeUs;work-input.buffers.clear();spCodec2Buffer copy;bool usesFrameReassembler false;if (buffer-size() 0u) {MutexedInput::Locked input(mInput);std::shared_ptrC2Buffer c2buffer;// 将buffer数据存到c2bufferif (!input-buffers-releaseBuffer(buffer, c2buffer, false)) {return -ENOENT;}// …if (input-frameReassembler) {usesFrameReassembler true;input-frameReassembler.process(buffer, items);} else {// …// 将c2buffer存到C2Work里。work-input.buffers.push_back(c2buffer);if (encryptedBlock) {work-input.infoBuffers.emplace_back(C2InfoBuffer::CreateLinearBuffer(kParamIndexEncryptedBuffer,encryptedBlock-share(0, blockSize, C2Fence())));}}} else if (eos) {// …}if (usesFrameReassembler) {// …} else {work-input.flags (C2FrameData::flags_t)flags;// TODO: fill infoswork-input.configUpdate std::move(mParamsToBeSet);if (tunnelFirstFrame) {C2StreamTunnelHoldRender::input tunnelHoldRender{0u / stream /,C2_TRUE / value */};work-input.configUpdate.push_back(C2Param::Copy(tunnelHoldRender));}work-worklets.clear();work-worklets.emplace_back(new C2Worklet);// 将C2Work存到items里items.push_back(std::move(work));eos eos buffer-size() 0u;}if (eos) {// …}c2_status_t err C2_OK;if (!items.empty()) {// …// 将C2Work数组提交给Component(通过hal层到真正实现编解码逻辑实现)这里是SimpleC2Component::queue_nb,详见4.9err mComponent-queue(items);}if (err ! C2_OK) {// …} else {// …释放buffer}feedInputBufferIfAvailableInternal();return err; }4.9 SimpleC2Component::queue_nb 这里把前面传过来的C2Work都放到mWorkQueue中然后发送了kWhatProcess消息触发处理逻辑。 c2_status_t SimpleC2Component::queue_nb(std::liststd::unique_ptrC2Work *const items) {{MutexedExecState::Locked state(mExecState);if (state-mState ! RUNNING) {return C2_BAD_STATE;}}bool queueWasEmpty false;{MutexedWorkQueue::Locked queue(mWorkQueue);queueWasEmpty queue-empty();// 将items里面的数据放到mWorkQueue中while (!items-empty()) {queue-push_back(std::move(items-front()));items-pop_front();}}if (queueWasEmpty) {// 发送kWhatProcess详见4.10 (new AMessage(WorkHandler::kWhatProcess, mHandler))-post();}return C2_OK; }4.10 SimpleC2Component::processQueue 这里主要就是会调用process方法这个方法是由子类实现的SimpleC2Component是用于管理流程框架的模版它的子类来实现具体编解码逻辑。 例如H264的编解码就是由子类C2SoftAacDec和C2SoftAacEnc实现的我们本节不会介绍编解码的细节下一节会介绍H264编解码的一些核心原理。 bool SimpleC2Component::processQueue() {// …{MutexedWorkQueue::Locked queue(mWorkQueue);if (queue-empty()) {return false;}generation queue-generation();drainMode queue-drainMode();isFlushPending queue-popPendingFlush();// 从队列中取出最前面的任务work queue-pop_front();hasQueuedWork !queue-empty();}if (isFlushPending) {// flush的回调这里SimpleC2Component是一个处理流程的架构最终需要由它的子类来实现对应生命周期所做的事。 c2_status_t err onFlush_sm();// …}if (!mOutputBlockPool) {// …创建用于管理输出Buffer的Pool}// …// … input内buffer的检测// 调用 process也是由子类实现的。 // 传入的参数是work和用于管理输出buffer的Poolprocess(work, mOutputBlockPool);// …return hasQueuedWork; }小结 本节介绍了MediaCodec编解码的流程从java层MediaCodec调用到JMediaCodec然后调用C层到MediaCodec通过发送对应流程的消息触发CCodec而里面通过一个CCodecBufferChannel来管理这些逻辑CCodecBufferChannel里面分input和output分别用于管理编解码他们中都有一个buffers用于管理所有buffer通过一个C2BlockPool来管理buffer的分配C2BlockPool内有一个Allocator会通过hal层进行最终的buffer分配释放。 CCodecBufferChannel工作会通过Component调用hal层传参数到SimpleC2ComponentSimpleC2Component的子类进行最终的编解码操作。 下一节我们会介绍H264编解码的核心原理。