void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { Mutex::Autolock autoLock(mMutex); if (!mExecuting) { return; } int cbi = findMatchingCodecBuffer_l(header); if (cbi < 0) { // This should never happen. ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header); return; } CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); // header->nFilledLen may not be the original value, so we can't compare // that to zero to see of this was the EOS buffer. Instead we just // see if the GraphicBuffer reference was null, which should only ever // happen for EOS. if (codecBuffer.mGraphicBuffer == NULL) { if (!(mEndOfStream && mEndOfStreamSent)) { // This can happen when broken code sends us the same buffer // twice in a row. ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer " "(buffer emptied twice?)"); } // No GraphicBuffer to deal with, no additional input or output is // expected, so just return. return; } if (EXTRA_CHECK) { // Pull the graphic buffer handle back out of the buffer, and confirm // that it matches expectations. OMX_U8* data = header->pBuffer; buffer_handle_t bufferHandle; memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { // should never happen ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", bufferHandle, codecBuffer.mGraphicBuffer->handle); CHECK(!"codecBufferEmptied: mismatched buffer"); } } // Find matching entry in our cached copy of the BufferQueue slots. // If we find a match, release that slot. If we don't, the BufferQueue // has dropped that GraphicBuffer, and there's nothing for us to release. int id = codecBuffer.mBuf; if (mBufferSlot[id] != NULL && mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) { if (id == mLatestSubmittedBufferId) { CHECK_GT(mLatestSubmittedBufferUseCount--, 0); } else { mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); } } // Mark the codec buffer as available by clearing the GraphicBuffer ref. codecBuffer.mGraphicBuffer = NULL; if (mNumFramesAvailable) { // Fill this codec buffer. CHECK(!mEndOfStreamSent); fillCodecBuffer_l(); } else if (mEndOfStream) { // No frames available, but EOS is pending, so use this buffer to // send that. submitEndOfInputStream_l(); } else if (mRepeatBufferDeferred) { bool success = repeatLatestSubmittedBuffer_l(); mRepeatBufferDeferred = false; } return; }
void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header, int fenceFd) { Mutex::Autolock autoLock(mMutex); if (!mExecuting) { return; } int cbi = findMatchingCodecBuffer_l(header); if (cbi < 0) { // This should never happen. ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header); if (fenceFd >= 0) { ::close(fenceFd); } return; } ALOGV("codecBufferEmptied h=%p size=%" PRIu32 " filled=%" PRIu32 " p=%p", header, header->nAllocLen, header->nFilledLen, header->pBuffer); CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); // header->nFilledLen may not be the original value, so we can't compare // that to zero to see of this was the EOS buffer. Instead we just // see if the GraphicBuffer reference was null, which should only ever // happen for EOS. if (codecBuffer.mGraphicBuffer == NULL) { if (!(mEndOfStream && mEndOfStreamSent)) { // This can happen when broken code sends us the same buffer // twice in a row. ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer " "(buffer emptied twice?)"); } // No GraphicBuffer to deal with, no additional input or output is // expected, so just return. if (fenceFd >= 0) { ::close(fenceFd); } return; } if (EXTRA_CHECK && header->nAllocLen >= sizeof(MetadataBufferType)) { // Pull the graphic buffer handle back out of the buffer, and confirm // that it matches expectations. OMX_U8* data = header->pBuffer; MetadataBufferType type = *(MetadataBufferType *)data; if (type == kMetadataBufferTypeGrallocSource && header->nAllocLen >= sizeof(VideoGrallocMetadata)) { VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)data; if (grallocMeta.pHandle != codecBuffer.mGraphicBuffer->handle) { // should never happen ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", grallocMeta.pHandle, codecBuffer.mGraphicBuffer->handle); CHECK(!"codecBufferEmptied: mismatched buffer"); } } else if (type == kMetadataBufferTypeANWBuffer && header->nAllocLen >= sizeof(VideoNativeMetadata)) { VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)data; if (nativeMeta.pBuffer != codecBuffer.mGraphicBuffer->getNativeBuffer()) { // should never happen ALOGE("codecBufferEmptied: buffer is %p, expected %p", nativeMeta.pBuffer, codecBuffer.mGraphicBuffer->getNativeBuffer()); CHECK(!"codecBufferEmptied: mismatched buffer"); } } } // Find matching entry in our cached copy of the BufferQueue slots. // If we find a match, release that slot. If we don't, the BufferQueue // has dropped that GraphicBuffer, and there's nothing for us to release. int id = codecBuffer.mBuf; sp<Fence> fence = new Fence(fenceFd); if (mBufferSlot[id] != NULL && mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) { ALOGV("cbi %d matches bq slot %d, handle=%p", cbi, id, mBufferSlot[id]->handle); if (id == mLatestBufferId) { CHECK_GT(mLatestBufferUseCount--, 0); } else { releaseBuffer(id, codecBuffer.mFrameNumber, mBufferSlot[id], fence); } } else { ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d", cbi); // we will not reuse codec buffer, so there is no need to wait for fence } // Mark the codec buffer as available by clearing the GraphicBuffer ref. codecBuffer.mGraphicBuffer = NULL; if (mNumFramesAvailable) { // Fill this codec buffer. CHECK(!mEndOfStreamSent); ALOGV("buffer freed, %zu frames avail (eos=%d)", mNumFramesAvailable, mEndOfStream); fillCodecBuffer_l(); } else if (mEndOfStream) { // No frames available, but EOS is pending, so use this buffer to // send that. ALOGV("buffer freed, EOS pending"); submitEndOfInputStream_l(); } else if (mRepeatBufferDeferred) { bool success = repeatLatestBuffer_l(); if (success) { ALOGV("deferred repeatLatestBuffer_l SUCCESS"); } else { ALOGV("deferred repeatLatestBuffer_l FAILURE"); } mRepeatBufferDeferred = false; } return; }
void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { Mutex::Autolock autoLock(mMutex); CHECK(mExecuting); // could this happen if app stop()s early? int cbi = findMatchingCodecBuffer_l(header); if (cbi < 0) { // This should never happen. ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header); return; } ALOGV("codecBufferEmptied h=%p size=%lu filled=%lu p=%p", header, header->nAllocLen, header->nFilledLen, header->pBuffer); CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); // header->nFilledLen may not be the original value, so we can't compare // that to zero to see of this was the EOS buffer. Instead we just // see if the GraphicBuffer reference was null, which should only ever // happen for EOS. if (codecBuffer.mGraphicBuffer == NULL) { CHECK(mEndOfStream && mEndOfStreamSent); // No GraphicBuffer to deal with, no additional input or output is // expected, so just return. return; } if (EXTRA_CHECK) { // Pull the graphic buffer handle back out of the buffer, and confirm // that it matches expectations. OMX_U8* data = header->pBuffer; buffer_handle_t bufferHandle; memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { // should never happen ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", bufferHandle, codecBuffer.mGraphicBuffer->handle); CHECK(!"codecBufferEmptied: mismatched buffer"); } } // Find matching entry in our cached copy of the BufferQueue slots. // If we find a match, release that slot. If we don't, the BufferQueue // has dropped that GraphicBuffer, and there's nothing for us to release. // // (We could store "id" in CodecBuffer and avoid the slot search.) int id; for (id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) { if (mBufferSlot[id] == NULL) { continue; } if (mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) { ALOGV("cbi %d matches bq slot %d, handle=%p", cbi, id, mBufferSlot[id]->handle); mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); break; } } if (id == BufferQueue::NUM_BUFFER_SLOTS) { ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d", cbi); } // Mark the codec buffer as available by clearing the GraphicBuffer ref. codecBuffer.mGraphicBuffer = NULL; if (mNumFramesAvailable) { // Fill this codec buffer. CHECK(!mEndOfStreamSent); ALOGV("buffer freed, %d frames avail (eos=%d)", mNumFramesAvailable, mEndOfStream); fillCodecBuffer_l(); } else if (mEndOfStream) { // No frames available, but EOS is pending, so use this buffer to // send that. ALOGV("buffer freed, EOS pending"); submitEndOfInputStream_l(); } return; }