void queueFrameCallbackMethod(IntPtr userPtr, uint userData, QCamM_Err errcode, uint flags) { int state = Interlocked.CompareExchange(ref queueFrameReentranceState, QFRS_IN_CALLBACK, QFRS_NONE); if (state != QFRS_NONE) { string msg = callback_thread_msg + CheckCurrentThread() + " @start"; if (CrashIfCallbackReEntranceDetected) { throw new Exception(msg); } else { Trace.TraceError(msg); } } else { CheckCurrentThread(); } if (disposeSignal.Wait(0)) { return; } queueFrameCallbackErr = unchecked ((int)errcode); int bufferIdx = checked ((int)userData); QCamM_Frame qCamFrame = qCamFrameBuffers[bufferIdx]; bool ok = RingBufferForOutput.TryCopyIn <QCamM_Frame, VideoFrame>(copierDelegate, qCamFrame); if (!ok) { Trace.Write("!"); } // re-insert buffer into the driver's queue QueueFrame(bufferIdx, qCamFrame.bufferSize); state = Interlocked.CompareExchange(ref queueFrameReentranceState, QFRS_NONE, QFRS_IN_CALLBACK); if (state != QFRS_IN_CALLBACK) { string msg = callback_thread_msg + CheckCurrentThread() + " @end"; if (CrashIfCallbackReEntranceDetected) { throw new Exception("QCam callback is re-entrant (end"); } else { Trace.TraceError(msg); } } }
/// <summary> /// Copies data from QCam frame data structure to standardized VideoFrame structure /// which can be serialized over the wire /// </summary> void CopyDataForOutput(QCamM_Frame qFrame, VideoFrame outFrame) { outFrame.ErrorCode = qFrame.errorCode; outFrame.BitsPerPixel = qFrame.bits; outFrame.Width = qFrame.width; outFrame.Height = qFrame.height; lock (odometerLock) { uint newOdo = CounterUtils.UnwrapRolledCounter(QCam_counter_bits, odometer, qFrame.frameNumber); long nFrameDrops = newOdo - (long)odometer - 1; if (nFrameDrops > 0) { Trace.TraceWarning("QCam driver dropped {0} frames!", nFrameDrops); } odometer = newOdo; outFrame.FrameNumber = newOdo; } outFrame.TimeStamp = qFrame.timeStamp; IntPtr pSrc = qFrame.pBuffer; if (pSrc == IntPtr.Zero) { throw new ArgumentException("Got QCam frame buffer with null data pointer"); } uint nBytes = qFrame.size; outFrame.DataSizeBytes = nBytes; // if there is data available, there's a buffer of the correct size, and copy it if (nBytes > 0) { byte[] buffer = outFrame.Data; if ((buffer == null) || (buffer.Length != nBytes)) { buffer = new byte[nBytes]; } Lab.Utilities.CopyPointerToBuffer(pSrc, buffer, 0, nBytes); outFrame.Data = buffer; } else { outFrame.Data = new byte[0]; Trace.TraceWarning("Sending empty frame!"); } }
/// <summary> /// Preps a frame buffer and inserts it into the QCam streaming queue /// </summary> void QueueFrame(int frameNum, uint dataSize) { if ((frameNum < 0) || (dataSize < 1)) { throw new ArgumentOutOfRangeException(); } if (disposeSignal.Wait(0)) { return; } QCamM_Frame frame = qCamFrameBuffers[frameNum]; // check that buffer exists and is sized correctly if (frame == null) { frame = new QCamM_Frame(); qCamFrameBuffers[frameNum] = frame; } if (frame.bufferSize != dataSize) { // release existing buffer, if present if (frame.pBuffer != IntPtr.Zero) { xq.QCamM_Free(frame.pBuffer); } // update buffer size frame.bufferSize = (uint)dataSize; frame.pBuffer = xq.QCamM_Malloc((uint)dataSize); if (frame.pBuffer == IntPtr.Zero) { Trace.TraceError("QCam_malloc returned a null pointer!"); return; } } var err = xq.QCamM_QueueFrame(camera, frame, queueFrameCallbackDelegate, (uint)QCamM_qcCallbackFlags.qcCallbackDone, IntPtr.Zero, (uint)frameNum); if (err != QCamM_Err.qerrSuccess) { Trace.TraceWarning("QCamM_QueueFrame returned " + err.ToString()); } }