1587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden/* 2587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * Copyright 2014 The Android Open Source Project 3587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * 4587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * Licensed under the Apache License, Version 2.0 (the "License"); 5587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * you may not use this file except in compliance with the License. 6587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * You may obtain a copy of the License at 7587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * 8587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * http://www.apache.org/licenses/LICENSE-2.0 9587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * 10587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * Unless required by applicable law or agreed to in writing, software 11587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * distributed under the License is distributed on an "AS IS" BASIS, 12587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * See the License for the specific language governing permissions and 14587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden * limitations under the License. 15587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden */ 16587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 17587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden#define LOG_TAG "ScreenRecord" 18587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden//#define LOG_NDEBUG 0 19587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden#include <utils/Log.h> 20587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 21587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden#include <GLES2/gl2.h> 22587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden#include <GLES2/gl2ext.h> 23587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 24587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden#include "FrameOutput.h" 25587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 26587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFaddenusing namespace android; 27587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 28587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFaddenstatic const bool kShowTiming = false; // set to "true" for debugging 29587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFaddenstatic const int kGlBytesPerPixel = 4; // GL_RGBA 30587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFaddenstatic const int kOutBytesPerPixel = 3; // RGB only 31587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 32587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFaddeninline void FrameOutput::setValueLE(uint8_t* buf, uint32_t value) { 33587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // Since we're running on an Android device, we're (almost) guaranteed 34587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // to be little-endian, and (almost) guaranteed that unaligned 32-bit 35587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // writes will work without any performance penalty... but do it 36587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // byte-by-byte anyway. 37587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden buf[0] = (uint8_t) value; 38587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden buf[1] = (uint8_t) (value >> 8); 39587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden buf[2] = (uint8_t) (value >> 16); 40587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden buf[3] = (uint8_t) (value >> 24); 41587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden} 42587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 43587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFaddenstatus_t FrameOutput::createInputSurface(int width, int height, 44587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden sp<IGraphicBufferProducer>* pBufferProducer) { 45587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden status_t err; 46587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 47587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden err = mEglWindow.createPbuffer(width, height); 48587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (err != NO_ERROR) { 49587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return err; 50587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 51587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mEglWindow.makeCurrent(); 52587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 53587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden glViewport(0, 0, width, height); 54587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden glDisable(GL_DEPTH_TEST); 55587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden glDisable(GL_CULL_FACE); 56587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 57587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // Shader for rendering the external texture. 58587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden err = mExtTexProgram.setup(Program::PROGRAM_EXTERNAL_TEXTURE); 59587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (err != NO_ERROR) { 60587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return err; 61587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 62587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 63587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // Input side (buffers from virtual display). 64587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden glGenTextures(1, &mExtTextureName); 65587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (mExtTextureName == 0) { 66587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGE("glGenTextures failed: %#x", glGetError()); 67587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return UNKNOWN_ERROR; 68587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 69587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 70b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza sp<IGraphicBufferProducer> producer; 71b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza sp<IGraphicBufferConsumer> consumer; 72b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza BufferQueue::createBufferQueue(&producer, &consumer); 73b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza mGlConsumer = new GLConsumer(consumer, mExtTextureName, 74db2722a319d91a869ebc4dd618edbef43fd5b738Dan Stoza GL_TEXTURE_EXTERNAL_OES, true, false); 75587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mGlConsumer->setName(String8("virtual display")); 76587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mGlConsumer->setDefaultBufferSize(width, height); 776e6eaa7ac713ab6606726c3f76a9019ded97f018Pablo Ceballos producer->setMaxDequeuedBufferCount(4); 78587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE); 79587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 80587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mGlConsumer->setFrameAvailableListener(this); 81587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 82587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mPixelBuf = new uint8_t[width * height * kGlBytesPerPixel]; 83587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 84b278f5e70c001391779525fb4d3b024503ba9466Dan Stoza *pBufferProducer = producer; 85587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 86587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGD("FrameOutput::createInputSurface OK"); 87587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return NO_ERROR; 88587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden} 89587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 90e32106fd5175afdf939ae397aece9caf378a4912Benoit Gobystatus_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec, bool rawFrames) { 91587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden Mutex::Autolock _l(mMutex); 92587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGV("copyFrame %ld\n", timeoutUsec); 93587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 94587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (!mFrameAvailable) { 95587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden nsecs_t timeoutNsec = (nsecs_t)timeoutUsec * 1000; 96587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden int cc = mEventCond.waitRelative(mMutex, timeoutNsec); 97587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (cc == -ETIMEDOUT) { 98587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGV("cond wait timed out"); 99587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return ETIMEDOUT; 100587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } else if (cc != 0) { 101587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGW("cond wait returned error %d", cc); 102587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return cc; 103587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 104587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 105587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (!mFrameAvailable) { 106587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // This happens when Ctrl-C is hit. Apparently POSIX says that the 107587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // pthread wait call doesn't return EINTR, treating this instead as 108587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // an instance of a "spurious wakeup". We didn't get a frame, so 109587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // we just treat it as a timeout. 110587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return ETIMEDOUT; 111587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 112587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 113587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // A frame is available. Clear the flag for the next round. 114587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mFrameAvailable = false; 115587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 116587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden float texMatrix[16]; 117587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mGlConsumer->updateTexImage(); 118587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mGlConsumer->getTransformMatrix(texMatrix); 119587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 120587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // The data is in an external texture, so we need to render it to the 121587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // pbuffer to get access to RGB pixel data. We also want to flip it 122587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // upside-down for easy conversion to a bitmap. 123587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden int width = mEglWindow.getWidth(); 124587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden int height = mEglWindow.getHeight(); 125587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden status_t err = mExtTexProgram.blit(mExtTextureName, texMatrix, 0, 0, 126587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden width, height, true); 127587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (err != NO_ERROR) { 128587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return err; 129587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 130587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 131587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // GLES only guarantees that glReadPixels() will work with GL_RGBA, so we 132587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // need to get 4 bytes/pixel and reduce it. Depending on the size of the 133587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // screen and the device capabilities, this can take a while. 134587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden int64_t startWhenNsec, pixWhenNsec, endWhenNsec; 135587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (kShowTiming) { 136587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden startWhenNsec = systemTime(CLOCK_MONOTONIC); 137587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 138587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden GLenum glErr; 139587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, mPixelBuf); 140587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if ((glErr = glGetError()) != GL_NO_ERROR) { 141587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGE("glReadPixels failed: %#x", glErr); 142587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return UNKNOWN_ERROR; 143587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 144587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (kShowTiming) { 145587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden pixWhenNsec = systemTime(CLOCK_MONOTONIC); 146587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 147587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden reduceRgbaToRgb(mPixelBuf, width * height); 148587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (kShowTiming) { 149587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden endWhenNsec = systemTime(CLOCK_MONOTONIC); 150587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGD("got pixels (get=%.3f ms, reduce=%.3fms)", 151587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden (pixWhenNsec - startWhenNsec) / 1000000.0, 152587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden (endWhenNsec - pixWhenNsec) / 1000000.0); 153587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 154587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 155587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden size_t rgbDataLen = width * height * kOutBytesPerPixel; 156e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby 157e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby if (!rawFrames) { 158e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby // Fill out the header. 159e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby size_t headerLen = sizeof(uint32_t) * 5; 160e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen; 161e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby uint8_t header[headerLen]; 162e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby setValueLE(&header[0], packetLen); 163e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby setValueLE(&header[4], width); 164e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby setValueLE(&header[8], height); 165e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby setValueLE(&header[12], width * kOutBytesPerPixel); 166e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888); 167e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby fwrite(header, 1, headerLen, fp); 168e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby } 169587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 170587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // Currently using buffered I/O rather than writev(). Not expecting it 171587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // to make much of a difference, but it might be worth a test for larger 172587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // frame sizes. 173587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (kShowTiming) { 174587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden startWhenNsec = systemTime(CLOCK_MONOTONIC); 175587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 176587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden fwrite(mPixelBuf, 1, rgbDataLen, fp); 177587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden fflush(fp); 178587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (kShowTiming) { 179587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden endWhenNsec = systemTime(CLOCK_MONOTONIC); 180587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGD("wrote pixels (%.3f ms)", 181587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden (endWhenNsec - startWhenNsec) / 1000000.0); 182587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 183587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 184587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden if (ferror(fp)) { 185587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // errno may not be useful; log it anyway 186587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden ALOGE("write failed (errno=%d)", errno); 187587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return UNKNOWN_ERROR; 188587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 189587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 190587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden return NO_ERROR; 191587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden} 192587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 193587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFaddenvoid FrameOutput::reduceRgbaToRgb(uint8_t* buf, unsigned int pixelCount) { 194587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // Convert RGBA to RGB. 195587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // 196587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // Unaligned 32-bit accesses are allowed on ARM, so we could do this 197587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // with 32-bit copies advancing at different rates (taking care at the 198587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden // end to not go one byte over). 199587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden const uint8_t* readPtr = buf; 200587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden for (unsigned int i = 0; i < pixelCount; i++) { 201587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden *buf++ = *readPtr++; 202587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden *buf++ = *readPtr++; 203587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden *buf++ = *readPtr++; 204587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden readPtr++; 205587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden } 206587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden} 207587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden 208587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden// Callback; executes on arbitrary thread. 20904f101c35eaa90b1f95939afac30674ec1611e6fDan Stozavoid FrameOutput::onFrameAvailable(const BufferItem& /* item */) { 210587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden Mutex::Autolock _l(mMutex); 211587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mFrameAvailable = true; 212587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden mEventCond.signal(); 213587c6fefcd3c1d05c608ff511cf3534bc765256eAndy McFadden} 214