IEventSPtr OMXComponent::WaitForGeneric(const list<IEventSPtr> &lstEvents, unsigned int uTimeoutMs) { IEventSPtr pRes; uint32_t u32Sec; uint32_t u32NanoSec; m_pClock->GetCurrent(&u32Sec, &u32NanoSec); add_milliseconds(&u32Sec, &u32NanoSec, uTimeoutMs); bool bMatch = false; bool bFailure = false; // go until we either fail or succeed while ((!bFailure) && (!bMatch)) { // go through all things we _can_ match with ... for (list<IEventSPtr>::const_iterator lsi = lstEvents.begin(); lsi != lstEvents.end(); lsi++) { // determine what type of event this is IEvent *pEvent = lsi->get(); OMXEventData *pOMX = pEvent->ToEvent(); EmptyBufferDoneData *pEmpty = pEvent->ToEmpty(); FillBufferDoneData *pFill = pEvent->ToFill(); Lock(); if (pEmpty != NULL) { for (list<EmptyBufferDoneData>::iterator li = m_lstEmpty.begin(); li != m_lstEmpty.end(); li++) { if (li->pBuffer == pEmpty->pBuffer) { bMatch = true; m_lstEmpty.erase(li); pRes = *lsi; break; } } } // if we are waiting for an OMXEvent else if (pOMX != NULL) { for (list<OMXEventData>::iterator li = m_lstEvents.begin(); li != m_lstEvents.end(); li++) { // if we found the match if ((li->eEvent == pOMX->eEvent) && (pOMX->nData1 == li->nData1) && (pOMX->nData2 == li->nData2)) { bMatch = true; m_lstEvents.erase(li); // remove this item from the list because the caller knows about it now pRes = *lsi; break; // must break here to about segfault since we just called erase() } } } else if (pFill != NULL) { for (list<FillBufferDoneData>::iterator li = m_lstFill.begin(); li != m_lstFill.end(); li++) { if (li->pBuffer == pFill->pBuffer) { bMatch = true; m_lstFill.erase(li); pRes = *lsi; break; } } } // else this should never happen else { assert(false); } Unlock(); // if we found a match, we're done if (bMatch) { break; } } // end for // if we didn't get a match we need to wait for success or a timeout if (!bMatch) { Lock(); // If we got an error or timed out, then we're done // (this implicitly unlocks the mutex during the waiting period, then relocks it upon returning!) if (!m_pLocker->WaitForEvent(u32Sec, u32NanoSec)) { bFailure = true; } Unlock(); } } // end while we haven't succeeded or failed if (bFailure) { throw runtime_error("Waiting timed out"); } return pRes; }
int JPEG::decode(const char* data_in, unsigned long int length_in, char **out, unsigned int *width, unsigned int *height) { try { // start of image width_out = width; height_out = height; bool bDone = false; bool bFillCalled = false; int iBufIdx = 0; const char* data = data_in; unsigned int length = length_in; // feed source buffer into component while (!bDone) { // get buffer to fill OMX_BUFFERHEADERTYPE *pBufHeader = vpBufHeaders[iBufIdx]; iBufIdx++; // wraparound if necessary if (iBufIdx >= iBufferCount) { iBufIdx = 0; } size_t stBytesRead = (length > pBufHeader->nAllocLen) ? pBufHeader->nAllocLen : length; memcpy(pBufHeader->pBuffer, data, stBytesRead); data += stBytesRead; length -= stBytesRead; pBufHeader->nFilledLen = stBytesRead; pBufHeader->nOffset = 0; pBufHeader->nFlags = 0; // if we are at EOF if (length <= 0) { pBufHeader->nFlags = OMX_BUFFERFLAG_EOS; // notify that the stream is done bDone = true; } m_pCompDecode->EmptyThisBuffer(pBufHeader); bool bGotEmpty = false; // we need to get an empty ack after calling EmptyThisBuffer, // the only thing that can stand in our way is getting a port settings changed event. // For large JPEGs, more than one port settings changed event may occur (I haven't figured out why, I just handle it) // We also expect a port settings changed event if we have no output buffer and can't proceed without one. while ((!bGotEmpty) || (m_pBufOutput == NULL)) { // we could get either a "empty done" or a "port settings changed" at this point IEventSPtr ev = m_pCompDecode->WaitForEventOrEmpty(OMX_EventPortSettingsChanged, m_iOutPortDecode, 0, pBufHeader, TIMEOUT_MS); IEvent *pEv = ev.get(); OMXEventData *pEvOMX = pEv->ToEvent(); EmptyBufferDoneData *pEvEmpty = pEv->ToEmpty(); // if it's a port settings changed event if (pEvOMX != NULL) { // if we don't yet have an output buffer, then create one now if (m_pBufOutput == 0) { OnDecoderOutputChanged(); // setup output buffer } // else we already have an output buffer, so handle the event differently else { OnDecoderOutputChangedAgain(); } } // else if this is an empty event else if (pEvEmpty != NULL) { bGotEmpty = true; } // else this is unexpected else { throw runtime_error("Unexpected IEvent"); } } assert(m_pBufOutput != 0); assert(m_pHeaderOutput != 0); if (!bFillCalled) { m_pCompResize->FillThisBuffer(m_pHeaderOutput); bFillCalled = true; // don't want to call FillThisBuffer twice } } // end while !bDone // both of these should be true at this point, if they're not it's a bug in my code assert(m_pBufOutput != 0); assert(bFillCalled); // wait for fill to finish so we can grab our final buffer m_pCompResize->WaitForFill(m_pHeaderOutput, TIMEOUT_MS); // wait for "end of stream" events from decoder and resizer m_pCompDecode->WaitForEvent(OMX_EventBufferFlag, m_iOutPortDecode, OMX_BUFFERFLAG_EOS, TIMEOUT_MS); m_pCompResize->WaitForEvent(OMX_EventBufferFlag, m_iOutPortResize, OMX_BUFFERFLAG_EOS, TIMEOUT_MS); // at this point, we should have no events queued up at all; if we do, we have probably missed one somewhere assert(m_pCompDecode->GetPendingEventCount() == 0); assert(m_pCompDecode->GetPendingEmptyCount() == 0); assert(m_pCompDecode->GetPendingFillCount() == 0); assert(m_pCompResize->GetPendingEventCount() == 0); assert(m_pCompResize->GetPendingEmptyCount() == 0); assert(m_pCompResize->GetPendingFillCount() == 0); *out = (char *)malloc(width[0]*height[0]*4); memcpy(*out, m_pHeaderOutput->pBuffer, width[0]*height[0]*4); } catch (std::exception &ex) { printf("Exception: %s\n", ex.what()); m_pLogger->Log("Got exception:"); m_pLogger->Log(ex.what()); return 1; } return 0; }