【stagefrightplayer】4 OMX Codec介绍 (2/2)

4.1 看下 drainInputBuffers();实现

  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>

  
  
  1. 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. }

这里解释下,我们可能申请了多个输入缓冲区,因此是一个循环,先检查我们有没有权限使用即OWNED_BY_US,这一缓冲区获取完数据后会检测

kOnlySubmitOneInputBufferAtOneTime即每次只允许读一个包,否则循环都读满。

下面继续跟进drainInputBuffer(info),忽略无关代码:

  1. bool OMXCodec::drainInputBuffer(BufferInfo *info) {
  2. **********
  3. status_t err;
  4. bool signalEOS = false;
  5. int64_t timestampUs = 0;
  6. size_t offset = 0;
  7. int32_t n = 0;
  8. for (;;) {
  9. MediaBuffer *srcBuffer;
  10. err = mSource->read(&srcBuffer);
  11. size_t remainingBytes = info->mSize - offset;
  12. 下面是判断从extractor读取到的数据是不是超过了总大小
  13. if (srcBuffer->range_length() > remainingBytes) {
  14. if (offset == 0) {
  15. srcBuffer->release();
  16. srcBuffer = NULL;
  17. setState(ERROR);
  18. return false;
  19. }
  20. mLeftOverBuffer = srcBuffer;
  21. break;
  22. } memcpy((uint8_t *)info->mData + offset,
  23. (const uint8_t *)srcBuffer->data()
  24. + srcBuffer->range_offset(),
  25. srcBuffer->range_length());
  26. offset += srcBuffer->range_length();
  27. if (releaseBuffer) {
  28. srcBuffer->release();
  29. srcBuffer = NULL;
  30. }
  31. 数据读取完毕后将srcBufferrelease掉
  32. }
  33. err = mOMX->emptyBuffer(
  34. mNode, info->mBuffer, 0, offset,
  35. flags, timestampUs);
  36. info->mStatus = OWNED_BY_COMPONENT;
  37. }

这里读取完毕后将缓冲区的状态设置成OWNED_BY_COMPONENT 解码器就可以解码了

这里可以看出来读取数据时实现了一次拷贝~~,而不是用的同一块缓冲区,注意下

读取数据可以参考前面介绍的extractor的内容,比较简单不说了。

下面看读取数据完毕后调用mOMX->emptyBuffer都干了些啥

通过前面我们很容易的理解实际调用的是

omx::emptybufferèOMXNodeInstance::emptyBuffer,

从代码可以看到最终调用的是

((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer()

实际代码在SimpleSoftOMXComponent.cpp中,具体如下

  1. OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
  2. OMX_BUFFERHEADERTYPE *buffer) {
  3. sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id());
  4. msg->setPointer("header", buffer);
  5. msg->post();
  6. return OMX_ErrorNone;
  7. }
OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
       OMX_BUFFERHEADERTYPE *buffer) {
   sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id());
   msg->setPointer("header", buffer);
   msg->post();
   return OMX_ErrorNone;
}

可以看到就是发了一条命令kWhatEmptyThisBuffer

通过handler->id确定了自己发的还得自己收,处理函数如下:

  1. void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
  2. Mutex::Autolock autoLock(mLock);
  3. uint32_t msgType = msg->what();
  4. ALOGV("msgType = %d", msgType);
  5. switch (msgType) {
  6. ********
  7. case kWhatEmptyThisBuffer:
  8. case kWhatFillThisBuffer:
  9. {
  10. OMX_BUFFERHEADERTYPE *header;
  11. CHECK(msg->findPointer("header", (void **)&header));
  12. CHECK(mState == OMX_StateExecuting && mTargetState == mState);
  13. bool found = false;
  14. size_t portIndex = (kWhatEmptyThisBuffer == msgType)? header->nInputPortIndex: header->nOutputPortIndex;
  15. PortInfo *port = &mPorts.editItemAt(portIndex);
  16. for (size_t j = 0; j < port->mBuffers.size(); ++j) {
  17. BufferInfo *buffer = &port->mBuffers.editItemAt(j);
  18. if (buffer->mHeader == header) {
  19. CHECK(!buffer->mOwnedByUs);
  20. buffer->mOwnedByUs = true;
  21. CHECK((msgType == kWhatEmptyThisBuffer
  22. && port->mDef.eDir == OMX_DirInput)|| (port->mDef.eDir == OMX_DirOutput));
  23. port->mQueue.push_back(buffer);
  24. onQueueFilled(portIndex);
  25. found = true;
  26. break;
  27. }
  28. }
  29. CHECK(found);
  30. break;
  31. }
  32. default:
  33. TRESPASS();
  34. break;
  35. }
  36. }
void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &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中。

具体解释看代码中注释

  1. void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
  2. if (mSignalledError || mOutputPortSettingsChange != NONE) {
  3. return;
  4. }
  5. 获取输入输出链表
  6. List<BufferInfo *> &inQueue = getPortQueue(0);
  7. List<BufferInfo *> &outQueue = getPortQueue(1);
  8. while (!inQueue.empty() && !outQueue.empty()) {
  9. 各自取输入输出缓冲区中的第一个缓冲区
  10. BufferInfo *inInfo = *inQueue.begin();
  11. OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
  12. BufferInfo *outInfo = *outQueue.begin();
  13. OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
  14. 判断缓冲区是不是没有数据,若果第一个都没有那就是没有
  15. if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
  16. inQueue.erase(inQueue.begin());
  17. inInfo->mOwnedByUs = false;
  18. notifyEmptyBufferDone(inHeader);
  19. if (!mIsFirst) {
  20. // pad the end of the stream with 529 samples, since that many samples
  21. // were trimmed off the beginning when decoding started
  22. outHeader->nFilledLen =
  23. kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
  24. memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
  25. } else {
  26. // Since we never discarded frames from the start, we won't have
  27. // to add any padding at the end either.
  28. outHeader->nFilledLen = 0;
  29. }
  30. outHeader->nFlags = OMX_BUFFERFLAG_EOS;
  31. outQueue.erase(outQueue.begin());
  32. outInfo->mOwnedByUs = false;
  33. notifyFillBufferDone(outHeader);
  34. return;
  35. }
  36. 如果offset==0说明是第一包的开头,需要读取pts,请结合extractor理解
  37. if (inHeader->nOffset == 0) {
  38. mAnchorTimeUs = inHeader->nTimeStamp;
  39. mNumFramesOutput = 0;
  40. }
  41. mConfig->pInputBuffer =
  42. inHeader->pBuffer + inHeader->nOffset;
  43. mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
  44. mConfig->inputBufferMaxLength = 0;
  45. mConfig->inputBufferUsedLength = 0;
  46. mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
  47. mConfig->pOutputBuffer =
  48. reinterpret_cast<int16_t *>(outHeader->pBuffer);
  49. ERROR_CODE decoderErr;
  50. 上面是配置参数 下面调用自己的解码器进行解码
  51. if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
  52. != NO_DECODING_ERROR) {
  53. ***出错处理*
  54. 这里注意如果解码失败,则填充0数据,也就是静音帧
  55. // play silence instead.
  56. memset(outHeader->pBuffer,
  57. 0,
  58. mConfig->outputFrameSize * sizeof(int16_t));
  59. mConfig->inputBufferUsedLength = inHeader->nFilledLen;
  60. } else if (mConfig->samplingRate != mSamplingRate
  61. || mConfig->num_channels != mNumChannels) {
  62. 这里说明参数发生了改变,即采样率等改变了,需要重新设置输出
  63. mSamplingRate = mConfig->samplingRate;
  64. mNumChannels = mConfig->num_channels;
  65. notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
  66. mOutputPortSettingsChange = AWAITING_DISABLED;
  67. return;
  68. }
  69. if (mIsFirst) {
  70. mIsFirst = false;
  71. // The decoder delay is 529 samples, so trim that many samples off
  72. // the start of the first output buffer. This essentially makes this
  73. // decoder have zero delay, which the rest of the pipeline assumes.
  74. outHeader->nOffset =
  75. kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
  76. outHeader->nFilledLen =
  77. mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
  78. } else {
  79. outHeader->nOffset = 0;
  80. outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
  81. }
  82. outHeader->nTimeStamp =
  83. mAnchorTimeUs
  84. + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
  85. outHeader->nFlags = 0;
  86. CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
  87. inHeader->nOffset += mConfig->inputBufferUsedLength;
  88. inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
  89. mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
  90. 如果输入缓冲区数据都解码完了,则调用notifyEmptyBufferDone
  91. if (inHeader->nFilledLen == 0) {
  92. inInfo->mOwnedByUs = false;
  93. inQueue.erase(inQueue.begin());
  94. inInfo = NULL;
  95. notifyEmptyBufferDone(inHeader);
  96. inHeader = NULL;
  97. }
  98. outInfo->mOwnedByUs = false;
  99. outQueue.erase(outQueue.begin());
  100. outInfo = NULL;
  101. 这是将解码出来的数据告诉外部,通过调用notifyFillBufferDone
  102. notifyFillBufferDone(outHeader);
  103. outHeader = NULL;
  104. }
  105. }
void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
    if (mSignalledError || mOutputPortSettingsChange != NONE) {
        return;
    }
  
    获取输入输出链表
  
    List<BufferInfo *> &inQueue = getPortQueue(0);
    List<BufferInfo *> &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<int16_t *>(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、输入部分的清空

  1. void SoftOMXComponent::notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header) {
  2. (*mCallbacks->EmptyBufferDone)(
  3. mComponent, mComponent->pApplicationPrivate, header);
  4. }
void SoftOMXComponent::notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header) {
  
   (*mCallbacks->EmptyBufferDone)(
  
           mComponent, mComponent->pApplicationPrivate, header);
  
}

通知外面我们emptythisbuffer完工了,具体调用的是OMXNodeInstance中的方法,具体怎么传进去的,大家可以自己分析下:

  1. OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
  2. OMX_IN OMX_HANDLETYPE hComponent,
  3. OMX_IN OMX_PTR pAppData,
  4. OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
  5. OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
  6. if (instance->mDying) {
  7. return OMX_ErrorNone;
  8. }
  9. return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
  10. }
OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(  
       OMX_IN OMX_HANDLETYPE hComponent,  
       OMX_IN OMX_PTR pAppData,  
       OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {  
   OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);  
   if (instance->mDying) {  
       return OMX_ErrorNone;  
   } 
   return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);  
}

OMXNodeInstance的ownner是OMX,因此代码为

  1. OMX_ERRORTYPE OMX::OnEmptyBufferDone(
  2. node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
  3. ALOGV("OnEmptyBufferDone buffer=%p", pBuffer);
  4. omx_message msg;
  5. msg.type = omx_message::EMPTY_BUFFER_DONE;
  6. msg.node = node;
  7. msg.u.buffer_data.buffer = pBuffer;
  8. findDispatcher(node)->post(msg);
  9. return OMX_ErrorNone;
  10. }
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定义如下

  1. sp<OMX::CallbackDispatcher> OMX::findDispatcher(node_id node) {
  2. Mutex::Autolock autoLock(mLock);
  3. ssize_t index = mDispatchers.indexOfKey(node);
  4. return index < 0 ? NULL : mDispatchers.valueAt(index);
  5. }
sp<OMX::CallbackDispatcher> 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

  1. void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
  2. if (mOwner == NULL) {
  3. ALOGV("Would have dispatched a message to a node that's already gone.");
  4. return;
  5. }
  6. mOwner->onMessage(msg);
  7. }
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方法接收了

  1. void OMXNodeInstance::onMessage(const omx_message &msg) {
  2. if (msg.type == omx_message::FILL_BUFFER_DONE) {
  3. OMX_BUFFERHEADERTYPE *buffer =
  4. static_cast<OMX_BUFFERHEADERTYPE *>(
  5. msg.u.extended_buffer_data.buffer);
  6. BufferMeta *buffer_meta =
  7. static_cast<BufferMeta *>(buffer->pAppPrivate);
  8. buffer_meta->CopyFromOMX(buffer);
  9. }
  10. mObserver->onMessage(msg);
  11. }
void OMXNodeInstance::onMessage(const omx_message &msg) {
    if (msg.type == omx_message::FILL_BUFFER_DONE) {
        OMX_BUFFERHEADERTYPE *buffer =
            static_cast<OMX_BUFFERHEADERTYPE *>(
                    msg.u.extended_buffer_data.buffer);
  
        BufferMeta *buffer_meta =
            static_cast<BufferMeta *>(buffer->pAppPrivate);
  
        buffer_meta->CopyFromOMX(buffer);
    }
  
    mObserver->onMessage(msg);
}

而onMessage又将消息传递到 mObserver中,也就是在OMXCodec::Create中构造的OMXCodecObserver对象,其OnMessage实现如下

  1. virtual void onMessage(const omx_message &msg) {
  2. sp<OMXCodec> codec = mTarget.promote();
  3. if (codec.get() != NULL) {
  4. Mutex::Autolock autoLock(codec->mLock);
  5. codec->on_message(msg);
  6. codec.clear();
  7. }
  8. }
virtual void onMessage(const omx_message &msg) {
    sp<OMXCodec> codec = mTarget.promote();
  
    if (codec.get() != NULL) {
        Mutex::Autolock autoLock(codec->mLock);
        codec->on_message(msg);
        codec.clear();
    }
}

最终还是传递给了OMXCodec里,具体看下:

  1. void OMXCodec::on_message(const omx_message &msg) {
  2. switch (msg.type) {
  3. ************
  4. case omx_message::EMPTY_BUFFER_DONE:
  5. {
  6. IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
  7. Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
  8. size_t i = 0;
  9. while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
  10. ++i;
  11. }
  12. BufferInfo* info = &buffers->editItemAt(i);
  13. info->mStatus = OWNED_BY_US;
  14. // Buffer could not be released until empty buffer done is called.
  15. if (info->mMediaBuffer != NULL) {
  16. info->mMediaBuffer->release();
  17. info->mMediaBuffer = NULL;
  18. }
  19. drainInputBuffer(&buffers->editItemAt(i));
  20. break;
  21. }
  22. ****************
  23. }
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<BufferInfo> *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);

  1. void SoftOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) {
  2. (*mCallbacks->FillBufferDone)(
  3. mComponent, mComponent->pApplicationPrivate, header);
  4. }
void SoftOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) {
   (*mCallbacks->FillBufferDone)(
           mComponent, mComponent->pApplicationPrivate, header);
}

  1. OMX_ERRORTYPE OMX::OnFillBufferDone(
  2. node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
  3. ALOGV("OnFillBufferDone buffer=%p", pBuffer);
  4. omx_message msg;
  5. msg.type = omx_message::FILL_BUFFER_DONE;
  6. msg.node = node;
  7. msg.u.extended_buffer_data.buffer = pBuffer;
  8. msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
  9. msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
  10. msg.u.extended_buffer_data.flags = pBuffer->nFlags;
  11. msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
  12. msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
  13. msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer;
  14. findDispatcher(node)->post(msg);
  15. return OMX_ErrorNone;
  16. }
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中

  1. void OMXCodec::on_message(const omx_message &msg) {
  2. {
  3. case omx_message::FILL_BUFFER_DONE:
  4. info->mStatus = OWNED_BY_US;
  5. mFilledBuffers.push_back(i);
  6. mBufferFilled.signal();
  7. break;
  8. }
  9. }
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

  1. void OMXCodec::fillOutputBuffers() {
  2. CHECK_EQ((int)mState, (int)EXECUTING);
  3. Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
  4. for (size_t i = 0; i < buffers->size(); ++i) {
  5. BufferInfo *info = &buffers->editItemAt(i);
  6. if (info->mStatus == OWNED_BY_US) {
  7. fillOutputBuffer(&buffers->editItemAt(i));
  8. }
  9. }
  10. }
void OMXCodec::fillOutputBuffers() {
   CHECK_EQ((int)mState, (int)EXECUTING);
   Vector<BufferInfo> *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,启动输出

  1. void OMXCodec::fillOutputBuffer(BufferInfo *info) {
  2. **************
  3. status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
  4. info->mStatus = OWNED_BY_COMPONENT;
  5. }
void OMXCodec::fillOutputBuffer(BufferInfo *info) {
   **************
   status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
   info->mStatus = OWNED_BY_COMPONENT;
}

下面和解码流程类似,我们依次来看:

  1. status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
  2. Mutex::Autolock autoLock(mLock);
  3. OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
  4. header->nFilledLen = 0;
  5. header->nOffset = 0;
  6. header->nFlags = 0;
  7. OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
  8. return StatusFromOMXError(err);
  9. }
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中,也就是

  1. OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer(
  2. OMX_BUFFERHEADERTYPE *buffer) {
  3. sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler->id());
  4. msg->setPointer("header", buffer);
  5. msg->post();
  6. return OMX_ErrorNone;
  7. }
OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer( 
       OMX_BUFFERHEADERTYPE *buffer) { 
   sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler->id()); 
   msg->setPointer("header", buffer);
   msg->post();
   return OMX_ErrorNone;
}

同理,接收程序也在本文件中:

  1. void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
  2. Mutex::Autolock autoLock(mLock);
  3. uint32_t msgType = msg->what();
  4. ALOGV("msgType = %d", msgType);
  5. switch (msgType) {
  6. case kWhatEmptyThisBuffer:
  7. case kWhatFillThisBuffer:
  8. {
  9. OMX_BUFFERHEADERTYPE *header;
  10. CHECK(msg->findPointer("header", (void **)&header));
  11. CHECK(mState == OMX_StateExecuting && mTargetState == mState);
  12. bool found = false;
  13. size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
  14. header->nInputPortIndex: header->nOutputPortIndex;
  15. PortInfo *port = &mPorts.editItemAt(portIndex);
  16. for (size_t j = 0; j < port->mBuffers.size(); ++j) {
  17. BufferInfo *buffer = &port->mBuffers.editItemAt(j);
  18. if (buffer->mHeader == header) {
  19. CHECK(!buffer->mOwnedByUs);
  20. buffer->mOwnedByUs = true;
  21. CHECK((msgType == kWhatEmptyThisBuffer
  22. && port->mDef.eDir == OMX_DirInput)
  23. || (port->mDef.eDir == OMX_DirOutput));
  24. port->mQueue.push_back(buffer);
  25. onQueueFilled(portIndex);
  26. found = true;
  27. break;
  28. }
  29. }
  30. CHECK(found);
  31. break;
  32. }
  33. default:
  34. TRESPASS();
  35. break;
  36. }
  37. }
void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &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);

两个函数来推进播放进度。

【结束】


欢迎转载,请注明出处!

更多 0

-

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值