博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【stagefrightplayer】4 OMX Codec介绍 (2/2)
阅读量:2457 次
发布时间:2019-05-11

本文共 24950 字,大约阅读时间需要 83 分钟。

4.1 看下 drainInputBuffers();实现

[html]
  1. <PRE class=html name="code">void OMXCodec::drainInputBuffers() {
  2. for (size_t i = 0; i < buffers->size(); ++i) {
  3. BufferInfo *info = &buffers->editItemAt(i);
  4. if (info->mStatus != OWNED_BY_US) {
  5. continue;
  6. }
  7. if (!drainInputBuffer(info)) {
  8. break;
  9. }
  10. if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
  11. break;
  12. }
  13. }
  14. }</PRE>
[html]                         
void OMXCodec::drainInputBuffers() {
for (size_t i = 0; i < buffers->size(); ++i) {
BufferInfo *info = &buffers->editItemAt(i);
if (info->mStatus != OWNED_BY_US) {
continue;
}
if (!drainInputBuffer(info)) {
break;
}
if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
break;
}
}
}
void OMXCodec::drainInputBuffers() { for (size_t i = 0; i < buffers->size(); ++i) { BufferInfo *info = &buffers->editItemAt(i); if (info->mStatus != OWNED_BY_US) { continue; } if (!drainInputBuffer(info)) { break; } if (mFlags & kOnlySubmitOneInputBufferAtOneTime) { break; } }} 这里解释下,我们可能申请了多个输入缓冲区,因此是一个循环,先检查我们有没有权限使用即OWNED_BY_US,这一缓冲区获取完数据后会检测 kOnlySubmitOneInputBufferAtOneTime即每次只允许读一个包,否则循环都读满。 下面继续跟进drainInputBuffer(info),忽略无关代码:
[html]
bool OMXCodec::drainInputBuffer(BufferInfo *info) {
**********
status_t err;
bool signalEOS = false;
int64_t timestampUs =0;
size_t offset = 0;
int32_t n = 0;
for (;;) {
MediaBuffer *srcBuffer;
err = mSource->read(&srcBuffer);
size_t remainingBytes =info->mSize - offset;
下面是判断从extractor读取到的数据是不是超过了总大小
if (srcBuffer->range_length()> remainingBytes) {
if (offset == 0) {
srcBuffer->release();
srcBuffer = NULL;
setState(ERROR);
return false;
}
mLeftOverBuffer =srcBuffer;
break;
} memcpy((uint8_t *)info->mData + offset,
(const uint8_t *)srcBuffer->data()
+ srcBuffer->range_offset(),
srcBuffer->range_length());
offset += srcBuffer->range_length();
if (releaseBuffer) {
srcBuffer->release();
srcBuffer = NULL;
}
数据读取完毕后将srcBufferrelease掉
}
err = mOMX->emptyBuffer(
mNode, info->mBuffer, 0, offset,
flags, timestampUs);
info->mStatus =OWNED_BY_COMPONENT;
}
这里读取完毕后将缓冲区的状态设置成OWNED_BY_COMPONENT 解码器就可以解码了 这里可以看出来读取数据时实现了一次拷贝~~,而不是用的同一块缓冲区,注意下 读取数据可以参考前面介绍的extractor的内容,比较简单不说了。 下面看读取数据完毕后调用mOMX->emptyBuffer都干了些啥 通过前面我们很容易的理解实际调用的是 omx::emptybufferèOMXNodeInstance::emptyBuffer, 从代码可以看到最终调用的是 ((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer() 实际代码在SimpleSoftOMXComponent.cpp中,具体如下
[html]
OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
OMX_BUFFERHEADERTYPE *buffer) {
sp
msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id());
msg->setPointer("header", buffer);
msg->post();
return OMX_ErrorNone;
}
OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer( OMX_BUFFERHEADERTYPE *buffer) { sp
msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id()); msg->setPointer("header", buffer); msg->post(); return OMX_ErrorNone;} 可以看到就是发了一条命令kWhatEmptyThisBuffer 通过handler->id确定了自己发的还得自己收,处理函数如下:
[html]
void SimpleSoftOMXComponent::onMessageReceived(const sp
&msg) {
Mutex::Autolock autoLock(mLock);
uint32_t msgType =msg->what();
ALOGV("msgType = %d", msgType);
switch (msgType) {
********
case kWhatEmptyThisBuffer:
case kWhatFillThisBuffer:
{
OMX_BUFFERHEADERTYPE *header;
CHECK(msg->findPointer("header", (void **)&header));
CHECK(mState == OMX_StateExecuting &&mTargetState == mState);
bool found = false;
size_t portIndex = (kWhatEmptyThisBuffer == msgType)? header->nInputPortIndex: header->nOutputPortIndex;
PortInfo *port = &mPorts.editItemAt(portIndex);
for (size_t j = 0; j< port->mBuffers.size(); ++j) {
BufferInfo *buffer = &port->mBuffers.editItemAt(j);
if (buffer->mHeader == header) {
CHECK(!buffer->mOwnedByUs);
buffer->mOwnedByUs =true;
CHECK((msgType == kWhatEmptyThisBuffer
&& port->mDef.eDir == OMX_DirInput)|| (port->mDef.eDir == OMX_DirOutput));
port->mQueue.push_back(buffer);
onQueueFilled(portIndex);
found = true;
break;
}
}
CHECK(found);
break;
}
default:
TRESPASS();
break;
}
}
void SimpleSoftOMXComponent::onMessageReceived(const sp
&msg) { Mutex::Autolock autoLock(mLock); uint32_t msgType = msg->what(); ALOGV("msgType = %d", msgType); switch (msgType) {******** case kWhatEmptyThisBuffer: case kWhatFillThisBuffer: { OMX_BUFFERHEADERTYPE *header; CHECK(msg->findPointer("header", (void **)&header)); CHECK(mState == OMX_StateExecuting && mTargetState == mState); bool found = false; size_t portIndex = (kWhatEmptyThisBuffer == msgType)? header->nInputPortIndex: header->nOutputPortIndex; PortInfo *port = &mPorts.editItemAt(portIndex); for (size_t j = 0; j < port->mBuffers.size(); ++j) { BufferInfo *buffer = &port->mBuffers.editItemAt(j); if (buffer->mHeader == header) { CHECK(!buffer->mOwnedByUs); buffer->mOwnedByUs = true; CHECK((msgType == kWhatEmptyThisBuffer && port->mDef.eDir == OMX_DirInput)|| (port->mDef.eDir == OMX_DirOutput)); port->mQueue.push_back(buffer); onQueueFilled(portIndex); found = true; break; } } CHECK(found); break; } default: TRESPASS(); break; }} 从代码这里来看这两个case都走同一套代码,而且都是通过onQueueFilled来处理,这样我们就引出了实际的处理函数,也就是onQueueFilled, 以mp3为例这里具体实现在SoftMP3中。 具体解释看代码中注释
[html]
void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
if (mSignalledError || mOutputPortSettingsChange != NONE) {
return;
}
获取输入输出链表
List
&inQueue =getPortQueue(0);
List
&outQueue =getPortQueue(1); while (!inQueue.empty() && !outQueue.empty()) { 各自取输入输出缓冲区中的第一个缓冲区 BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader =inInfo->mHeader; BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader =outInfo->mHeader; 判断缓冲区是不是没有数据,若果第一个都没有那就是没有 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs =false; notifyEmptyBufferDone(inHeader); if (!mIsFirst) { // pad the end of the stream with 529 samples, since that many samples // were trimmed off the beginning when decoding started outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); memset(outHeader->pBuffer, 0, outHeader->nFilledLen); } else { // Since we never discarded frames from the start, we won't have // to add any padding at the end either. outHeader->nFilledLen =0; } outHeader->nFlags =OMX_BUFFERFLAG_EOS; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs =false; notifyFillBufferDone(outHeader); return; } 如果offset==0说明是第一包的开头,需要读取pts,请结合extractor理解 if (inHeader->nOffset == 0) { mAnchorTimeUs =inHeader->nTimeStamp; mNumFramesOutput = 0; } mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset; mConfig->inputBufferCurrentLength =inHeader->nFilledLen; mConfig->inputBufferMaxLength =0; mConfig->inputBufferUsedLength =0; mConfig->outputFrameSize =kOutputBufferSize / sizeof(int16_t); mConfig->pOutputBuffer = reinterpret_cast
(outHeader->pBuffer); ERROR_CODE decoderErr; 上面是配置参数 下面调用自己的解码器进行解码 if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf)) != NO_DECODING_ERROR) { ***出错处理* 这里注意如果解码失败,则填充0数据,也就是静音帧 // play silence instead. memset(outHeader->pBuffer, 0, mConfig->outputFrameSize * sizeof(int16_t)); mConfig->inputBufferUsedLength =inHeader->nFilledLen; } else if (mConfig->samplingRate != mSamplingRate || mConfig->num_channels != mNumChannels) { 这里说明参数发生了改变,即采样率等改变了,需要重新设置输出 mSamplingRate =mConfig->samplingRate; mNumChannels = mConfig->num_channels; notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange =AWAITING_DISABLED; return; } if (mIsFirst) { mIsFirst = false; // The decoder delay is 529 samples, so trim that many samples off // the start of the first output buffer. This essentially makes this // decoder have zero delay, which the rest of the pipeline assumes. outHeader->nOffset = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset; } else { outHeader->nOffset =0; outHeader->nFilledLen =mConfig->outputFrameSize * sizeof(int16_t); } outHeader->nTimeStamp = mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate; outHeader->nFlags =0; CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength); inHeader->nOffset += mConfig->inputBufferUsedLength; inHeader->nFilledLen -= mConfig->inputBufferUsedLength; mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; 如果输入缓冲区数据都解码完了,则调用notifyEmptyBufferDone if (inHeader->nFilledLen == 0) { inInfo->mOwnedByUs =false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } outInfo->mOwnedByUs =false; outQueue.erase(outQueue.begin()); outInfo = NULL; 这是将解码出来的数据告诉外部,通过调用notifyFillBufferDone notifyFillBufferDone(outHeader); outHeader = NULL; } } void SoftMP3::onQueueFilled(OMX_U32 portIndex) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } 获取输入输出链表 List
&inQueue = getPortQueue(0); List
&outQueue = getPortQueue(1); while (!inQueue.empty() && !outQueue.empty()) { 各自取输入输出缓冲区中的第一个缓冲区 BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 判断缓冲区是不是没有数据,若果第一个都没有那就是没有 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); if (!mIsFirst) { // pad the end of the stream with 529 samples, since that many samples // were trimmed off the beginning when decoding started outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); memset(outHeader->pBuffer, 0, outHeader->nFilledLen); } else { // Since we never discarded frames from the start, we won't have // to add any padding at the end either. outHeader->nFilledLen = 0; } outHeader->nFlags = OMX_BUFFERFLAG_EOS; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); return; } 如果offset==0说明是第一包的开头,需要读取pts,请结合extractor理解 if (inHeader->nOffset == 0) { mAnchorTimeUs = inHeader->nTimeStamp; mNumFramesOutput = 0; } mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset; mConfig->inputBufferCurrentLength = inHeader->nFilledLen; mConfig->inputBufferMaxLength = 0; mConfig->inputBufferUsedLength = 0; mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t); mConfig->pOutputBuffer = reinterpret_cast
(outHeader->pBuffer); ERROR_CODE decoderErr; 上面是配置参数 下面调用自己的解码器进行解码 if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf)) != NO_DECODING_ERROR) { ***出错处理* 这里注意如果解码失败,则填充0数据,也就是静音帧 // play silence instead. memset(outHeader->pBuffer, 0, mConfig->outputFrameSize * sizeof(int16_t)); mConfig->inputBufferUsedLength = inHeader->nFilledLen; } else if (mConfig->samplingRate != mSamplingRate || mConfig->num_channels != mNumChannels) { 这里说明参数发生了改变,即采样率等改变了,需要重新设置输出 mSamplingRate = mConfig->samplingRate; mNumChannels = mConfig->num_channels; notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; return; } if (mIsFirst) { mIsFirst = false; // The decoder delay is 529 samples, so trim that many samples off // the start of the first output buffer. This essentially makes this // decoder have zero delay, which the rest of the pipeline assumes. outHeader->nOffset = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t); outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset; } else { outHeader->nOffset = 0; outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t); } outHeader->nTimeStamp = mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate; outHeader->nFlags = 0; CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength); inHeader->nOffset += mConfig->inputBufferUsedLength; inHeader->nFilledLen -= mConfig->inputBufferUsedLength; mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; 如果输入缓冲区数据都解码完了,则调用notifyEmptyBufferDone if (inHeader->nFilledLen == 0) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; 这是将解码出来的数据告诉外部,通过调用notifyFillBufferDone notifyFillBufferDone(outHeader); outHeader = NULL; }} 下面分析下,如何将输入缓冲区释放和将输出缓冲区中的数据传递出去 A、输入部分的清空 [html] void SoftOMXComponent::notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header) { (*mCallbacks->EmptyBufferDone)( mComponent, mComponent->pApplicationPrivate, header); } void SoftOMXComponent::notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header) { (*mCallbacks->EmptyBufferDone)( mComponent, mComponent->pApplicationPrivate, header); } 通知外面我们emptythisbuffer完工了,具体调用的是OMXNodeInstance中的方法,具体怎么传进去的,大家可以自己分析下: [html] OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { OMXNodeInstance *instance =static_cast
(pAppData); if (instance->mDying) { return OMX_ErrorNone; } return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer); } OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { OMXNodeInstance *instance = static_cast
(pAppData); if (instance->mDying) { return OMX_ErrorNone; } return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer); } OMXNodeInstance的ownner是OMX,因此代码为 [html] OMX_ERRORTYPE OMX::OnEmptyBufferDone( node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGV("OnEmptyBufferDone buffer=%p", pBuffer); omx_message msg; msg.type = omx_message::EMPTY_BUFFER_DONE; msg.node = node; msg.u.buffer_data.buffer =pBuffer; findDispatcher(node)->post(msg); return OMX_ErrorNone; } OMX_ERRORTYPE OMX::OnEmptyBufferDone( node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGV("OnEmptyBufferDone buffer=%p", pBuffer); omx_message msg; msg.type = omx_message::EMPTY_BUFFER_DONE; msg.node = node; msg.u.buffer_data.buffer = pBuffer; findDispatcher(node)->post(msg); return OMX_ErrorNone; } 其中findDispatcher定义如下 [html] sp
OMX::findDispatcher(node_id node) { Mutex::Autolock autoLock(mLock); ssize_t index =mDispatchers.indexOfKey(node); return index < 0 ? NULL : mDispatchers.valueAt(index); } sp
OMX::findDispatcher(node_id node) { Mutex::Autolock autoLock(mLock); ssize_t index = mDispatchers.indexOfKey(node); return index < 0 ? NULL : mDispatchers.valueAt(index);} 这里mDispatcher在之前allocateNode中通过mDispatchers.add(*node, new CallbackDispatcher(instance)); 创建的 看下实际的实现可知道,CallbackDispatcher的post方法最终会调用dispatch [html] void OMX::CallbackDispatcher::dispatch(const omx_message &msg) { if (mOwner == NULL) { ALOGV("Would have dispatched a message to a node that's already gone."); return; } mOwner->onMessage(msg); } void OMX::CallbackDispatcher::dispatch(const omx_message &msg) { if (mOwner == NULL) { ALOGV("Would have dispatched a message to a node that's already gone."); return; } mOwner->onMessage(msg);} 而owner是OMXNodeInstance,因此消息饶了一圈还是到了OMXNodeInstance的OnMessage方法接收了 [html] void OMXNodeInstance::onMessage(const omx_message &msg) { if (msg.type == omx_message::FILL_BUFFER_DONE) { OMX_BUFFERHEADERTYPE *buffer = static_cast
( msg.u.extended_buffer_data.buffer); BufferMeta *buffer_meta = static_cast
(buffer->pAppPrivate); buffer_meta->CopyFromOMX(buffer); } mObserver->onMessage(msg); } void OMXNodeInstance::onMessage(const omx_message &msg) { if (msg.type == omx_message::FILL_BUFFER_DONE) { OMX_BUFFERHEADERTYPE *buffer = static_cast
( msg.u.extended_buffer_data.buffer); BufferMeta *buffer_meta = static_cast
(buffer->pAppPrivate); buffer_meta->CopyFromOMX(buffer); } mObserver->onMessage(msg);} 而onMessage又将消息传递到 mObserver中,也就是在OMXCodec::Create中构造的OMXCodecObserver对象,其OnMessage实现如下 [html] virtual void onMessage(const omx_message &msg) { sp
codec = mTarget.promote(); if (codec.get() != NULL) { Mutex::Autolock autoLock(codec->mLock); codec->on_message(msg); codec.clear(); } } virtual void onMessage(const omx_message &msg) { sp
codec = mTarget.promote(); if (codec.get() != NULL) { Mutex::Autolock autoLock(codec->mLock); codec->on_message(msg); codec.clear(); }} 最终还是传递给了OMXCodec里,具体看下: [html] void OMXCodec::on_message(const omx_message &msg) { switch (msg.type) { ************ case omx_message::EMPTY_BUFFER_DONE: { IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer; Vector
*buffers = &mPortBuffers[kPortIndexInput]; size_t i = 0; while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) { ++i; } BufferInfo* info = &buffers->editItemAt(i); info->mStatus =OWNED_BY_US; // Buffer could not be released until empty buffer done is called. if (info->mMediaBuffer != NULL) { info->mMediaBuffer->release(); info->mMediaBuffer =NULL; } drainInputBuffer(&buffers->editItemAt(i)); break; } **************** } void OMXCodec::on_message(const omx_message &msg) { switch (msg.type) { ************ case omx_message::EMPTY_BUFFER_DONE: { IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer; Vector
*buffers = &mPortBuffers[kPortIndexInput]; size_t i = 0; while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) { ++i; } BufferInfo* info = &buffers->editItemAt(i); info->mStatus = OWNED_BY_US; // Buffer could not be released until empty buffer done is called. if (info->mMediaBuffer != NULL) { info->mMediaBuffer->release(); info->mMediaBuffer = NULL; } drainInputBuffer(&buffers->editItemAt(i)); break; } **************** } 这部分很绕,但搞清楚就好了,请大家仔细阅读,此处虽然调用了info->mMediaBuffer->release();但是由于其引用始终大于0,因此不会真正的release 二是当release完毕后,会调用drainInputBuffer(&buffers->editItemAt(i));来填充数据 也就是说当我们启动一次解码播放后,会在此处循环读取数和据解码数据。而输出数据在后面的filloutbuffer中。 B、输出数据的清空notifyFillBufferDone(outHeader); [html] void SoftOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) { (*mCallbacks->FillBufferDone)( mComponent, mComponent->pApplicationPrivate, header); } void SoftOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) { (*mCallbacks->FillBufferDone)( mComponent, mComponent->pApplicationPrivate, header);} [html] OMX_ERRORTYPE OMX::OnFillBufferDone( node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGV("OnFillBufferDone buffer=%p", pBuffer); omx_message msg; msg.type = omx_message::FILL_BUFFER_DONE; msg.node = node; msg.u.extended_buffer_data.buffer =pBuffer; msg.u.extended_buffer_data.range_offset =pBuffer->nOffset; msg.u.extended_buffer_data.range_length =pBuffer->nFilledLen; msg.u.extended_buffer_data.flags =pBuffer->nFlags; msg.u.extended_buffer_data.timestamp =pBuffer->nTimeStamp; msg.u.extended_buffer_data.platform_private =pBuffer->pPlatformPrivate; msg.u.extended_buffer_data.data_ptr =pBuffer->pBuffer; findDispatcher(node)->post(msg); return OMX_ErrorNone; } OMX_ERRORTYPE OMX::OnFillBufferDone( node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGV("OnFillBufferDone buffer=%p", pBuffer); omx_message msg; msg.type = omx_message::FILL_BUFFER_DONE; msg.node = node; msg.u.extended_buffer_data.buffer = pBuffer; msg.u.extended_buffer_data.range_offset = pBuffer->nOffset; msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; msg.u.extended_buffer_data.flags = pBuffer->nFlags; msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; findDispatcher(node)->post(msg); return OMX_ErrorNone; } 最终处理在OMXCodec.cpp中 [html] void OMXCodec::on_message(const omx_message &msg) { { case omx_message::FILL_BUFFER_DONE: info->mStatus =OWNED_BY_US; mFilledBuffers.push_back(i); mBufferFilled.signal(); break; } } void OMXCodec::on_message(const omx_message &msg) {{case omx_message::FILL_BUFFER_DONE: info->mStatus = OWNED_BY_US; mFilledBuffers.push_back(i); mBufferFilled.signal(); break; }} 主体就这么几句,先将mStatus设置成OWNED_BY_US,这样component便不能操作了,后面将这个buffer push到mFilledBuffers中。 4.2 fillOutputBuffers [html] void OMXCodec::fillOutputBuffers() { CHECK_EQ((int)mState, (int)EXECUTING); Vector
*buffers = &mPortBuffers[kPortIndexOutput]; for (size_t i = 0; i< buffers->size(); ++i) { BufferInfo *info = &buffers->editItemAt(i); if (info->mStatus == OWNED_BY_US) { fillOutputBuffer(&buffers->editItemAt(i)); } } } void OMXCodec::fillOutputBuffers() { CHECK_EQ((int)mState, (int)EXECUTING); Vector
*buffers = &mPortBuffers[kPortIndexOutput]; for (size_t i = 0; i < buffers->size(); ++i) { BufferInfo *info = &buffers->editItemAt(i); if (info->mStatus == OWNED_BY_US) { fillOutputBuffer(&buffers->editItemAt(i)); } }} 找到一个输出缓冲区bufferinfo,启动输出 [html] void OMXCodec::fillOutputBuffer(BufferInfo *info) { ************** status_t err = mOMX->fillBuffer(mNode, info->mBuffer); info->mStatus =OWNED_BY_COMPONENT; } void OMXCodec::fillOutputBuffer(BufferInfo *info) { ************** status_t err = mOMX->fillBuffer(mNode, info->mBuffer); info->mStatus = OWNED_BY_COMPONENT;} 下面和解码流程类似,我们依次来看: [html] status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) { Mutex::Autolock autoLock(mLock); OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; header->nFilledLen =0; header->nOffset =0; header->nFlags =0; OMX_ERRORTYPE err =OMX_FillThisBuffer(mHandle, header); return StatusFromOMXError(err); } status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) { Mutex::Autolock autoLock(mLock); OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; header->nFilledLen = 0; header->nOffset = 0; header->nFlags = 0; OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header); return StatusFromOMXError(err); } 进行一些初始化后,调用进入了softMP3中,也就是 [html] OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer( OMX_BUFFERHEADERTYPE *buffer) { sp
msg = new AMessage(kWhatFillThisBuffer, mHandler->id()); msg->setPointer("header", buffer); msg->post(); return OMX_ErrorNone; } OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer( OMX_BUFFERHEADERTYPE *buffer) { sp
msg = new AMessage(kWhatFillThisBuffer, mHandler->id()); msg->setPointer("header", buffer); msg->post(); return OMX_ErrorNone;} 同理,接收程序也在本文件中: [html] void SimpleSoftOMXComponent::onMessageReceived(const sp
&msg) { Mutex::Autolock autoLock(mLock); uint32_t msgType =msg->what(); ALOGV("msgType = %d", msgType); switch (msgType) { case kWhatEmptyThisBuffer: case kWhatFillThisBuffer: { OMX_BUFFERHEADERTYPE *header; CHECK(msg->findPointer("header", (void **)&header)); CHECK(mState == OMX_StateExecuting &&mTargetState == mState); bool found = false; size_t portIndex = (kWhatEmptyThisBuffer == msgType)? header->nInputPortIndex: header->nOutputPortIndex; PortInfo *port = &mPorts.editItemAt(portIndex); for (size_t j = 0; j< port->mBuffers.size(); ++j) { BufferInfo *buffer = &port->mBuffers.editItemAt(j); if (buffer->mHeader == header) { CHECK(!buffer->mOwnedByUs); buffer->mOwnedByUs =true; CHECK((msgType == kWhatEmptyThisBuffer && port->mDef.eDir == OMX_DirInput) || (port->mDef.eDir == OMX_DirOutput)); port->mQueue.push_back(buffer); onQueueFilled(portIndex); found = true; break; } } CHECK(found); break; } default: TRESPASS(); break; } } void SimpleSoftOMXComponent::onMessageReceived(const sp
&msg) { Mutex::Autolock autoLock(mLock); uint32_t msgType = msg->what(); ALOGV("msgType = %d", msgType); switch (msgType) { case kWhatEmptyThisBuffer: case kWhatFillThisBuffer: { OMX_BUFFERHEADERTYPE *header; CHECK(msg->findPointer("header", (void **)&header)); CHECK(mState == OMX_StateExecuting && mTargetState == mState); bool found = false; size_t portIndex = (kWhatEmptyThisBuffer == msgType)? header->nInputPortIndex: header->nOutputPortIndex; PortInfo *port = &mPorts.editItemAt(portIndex); for (size_t j = 0; j < port->mBuffers.size(); ++j) { BufferInfo *buffer = &port->mBuffers.editItemAt(j); if (buffer->mHeader == header) { CHECK(!buffer->mOwnedByUs); buffer->mOwnedByUs = true; CHECK((msgType == kWhatEmptyThisBuffer && port->mDef.eDir == OMX_DirInput) || (port->mDef.eDir == OMX_DirOutput)); port->mQueue.push_back(buffer); onQueueFilled(portIndex); found = true; break; } } CHECK(found); break; } default: TRESPASS(); break; } } 也会调用void SoftMP3::onQueueFilled执行一次解码操作,然后再通过 notifyEmptyBufferDone(inHeader); notifyFillBufferDone(outHeader); 两个函数来推进播放进度。 【结束】 欢迎转载,请注明出处! 更多 上一篇: 下一篇: -  
你可能感兴趣的文章
32位系统能够识别多达内存_C ++程序可打印多达N个术语的卢卡斯系列
查看>>
Java ArrayList trimToSize()方法与示例
查看>>
Java Byte类parseByte()方法的示例
查看>>
java 方法 示例_Java CollectionsEmptyMap()方法与示例
查看>>
Java FileDescriptor valid()方法与示例
查看>>
java define_Java Integer类的define()方法与示例
查看>>
strictmath_Java StrictMath toDegrees()方法与示例
查看>>
奇数 横竖斜总和相等_将集合分成相等总和的k个子集
查看>>
data.add方法c#_清单 .Add()方法与C#中的示例
查看>>
js 验证护照_护照本地策略第1部分| Node.js
查看>>
scala编程_Scala概述| Scala编程教程
查看>>
stl vector 函数_vector :: capacity()函数以及C ++ STL中的示例
查看>>
Java BigInteger类| negate()方法与示例
查看>>
c++中对象数组的初始化_C ++中对象的动态初始化
查看>>
Java CharArrayWriter reset()方法及示例
查看>>
Java类类getMethod()方法及示例
查看>>
Java IdentityHashMap clone()方法与示例
查看>>
java timezone_Java TimeZone hasSameRules()方法与示例
查看>>
PHP Superglobals能力倾向问题与解答
查看>>
密码学,把字母转换为数字_密码学转换技术
查看>>