NTSTATUS CaptureFilterVideoInPinProcess ( IN PKSPIN pKSPin ) { PKSSTREAM_POINTER pStreamPointer = NULL; NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; DbgPrint("CaptureFilterVideoInPinProcess"); //parameters valid? if( !pKSPin ) { DbgPrint("Error: CaptureFilterVideoInPinProcess: Invalid argument"); return STATUS_UNSUCCESSFUL; } //get next available system buffer pStreamPointer = KsPinGetLeadingEdgeStreamPointer( pKSPin, KSSTREAM_POINTER_STATE_LOCKED); if( !pStreamPointer ) { DbgPrint("Error: CaptureFilterVideoInPinProcess: Streampointer invalid"); return STATUS_UNSUCCESSFUL; } if( !(pStreamPointer->StreamHeader) ) { DbgPrint( "Error: AnlgVideoInPinProcess: Streampointer header invalid"); if(KsStreamPointerAdvance(pStreamPointer) != STATUS_SUCCESS) { DbgPrint( "Warning: AnlgVideoInPinProcess:\ Streampointer advacement failed"); }
NTSTATUS CStillPin::Process () /*++ Routine Description: The process dispatch for the pin bridges to this location. We handle setting up scatter gather mappings, etc... Arguments: None Return Value: Success / Failure --*/ { PAGED_CODE(); NTSTATUS Status = STATUS_SUCCESS; PKSSTREAM_POINTER Leading=NULL; SnPrint(DEBUGLVL_VERBOSE, ("Enter CStillPin::Process\n")); ASSERT(m_Pin); if (!m_Device) { DBGU_ERROR("DeviceState is not KSSTATE_RUN or m_Device of CStillPin is NULL!\n"); return STATUS_UNSUCCESSFUL; } if (m_Pin->DeviceState != KSSTATE_RUN) { DBGU_WARNING("Stream State is not KSSTATE_RUN ..\n"); return STATUS_UNSUCCESSFUL; } KsPinAcquireProcessingMutex(m_Pin); Leading = KsPinGetLeadingEdgeStreamPointer ( m_Pin, KSSTREAM_POINTER_STATE_LOCKED ); // // Find stream pointer that has Data buffer // while (NT_SUCCESS (Status) && Leading) { // // If no data is present in the Leading edge stream pointer, just // move on to the next frame // if ( NULL == Leading -> StreamHeader -> Data ) { Status = KsStreamPointerAdvance(Leading); continue; } break; } if (Leading && m_VideoInfoHeader) { // // fill Stream header // Leading->StreamHeader->DataUsed = 0; DBGU_TRACE("buffer Remaining = %d\n",Leading->OffsetOut.Remaining); if (Leading->OffsetOut.Remaining >= m_VideoInfoHeader->bmiHeader.biSizeImage) { Leading -> StreamHeader -> Duration = m_VideoInfoHeader -> AvgTimePerFrame; Leading -> StreamHeader -> PresentationTime.Numerator = Leading -> StreamHeader -> PresentationTime.Denominator = 1; Status = m_Device->FrameReadingProcess( m_Pin, Leading->StreamHeader ); /*// shawn 2011/07/27 for testing +++++ // // Write image data to file. // IO_STATUS_BLOCK ioStatusBlock; HANDLE fh; LARGE_INTEGER ByteOffset; UNICODE_STRING uSnapShotFileName; OBJECT_ATTRIBUTES oa; UCHAR p[SNAPSHOT_FILE_HDR_SIZE]; WCHAR *wssfn=NULL; wssfn = new (NonPagedPool) WCHAR[MAX_PATH]; //if(!wssfn) // break; DBGU_TRACE("Still Process: Start Save Image file! \n"); swprintf(wssfn, L"\\DosDevices\\C:\\Still_%ws",m_Device->pdx->pVideoDevice->m_SnapShotFileName); RtlInitUnicodeString(&uSnapShotFileName, wssfn); InitializeObjectAttributes(&oa,&uSnapShotFileName, OBJ_CASE_INSENSITIVE,NULL,NULL); if (NT_SUCCESS(ZwCreateFile( &fh, GENERIC_WRITE | SYNCHRONIZE, &oa, &ioStatusBlock, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0))) { ByteOffset.QuadPart = 0; ZwWriteFile(fh, NULL, NULL, NULL, &ioStatusBlock, Leading->StreamHeader->Data, Leading->StreamHeader->DataUsed, &ByteOffset, NULL); ZwClose(fh); }//zwCreateFile is ok if (wssfn) delete wssfn; // shawn 2011/07/27 for testing -----*/ // shawn 2011/07/28 remove for fixing method 2 MJPEG snapshot issue /*if (m_Clock) { LONGLONG ClockTime = m_Clock -> GetTime (); Leading -> StreamHeader -> PresentationTime.Time = ClockTime; Leading -> StreamHeader -> OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_FLUSHONPAUSE | KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID; } else*/ { // // If there is no clock, don't time stamp the packets. // Leading -> StreamHeader -> PresentationTime.Time = 0; Leading -> StreamHeader -> OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_FLUSHONPAUSE; } // // Advances StreamPointer the specified number of bytes into the stream // and unlocks it. // KsStreamPointerAdvanceOffsetsAndUnlock( Leading, 0, /*m_VideoInfoHeader->bmiHeader.biSizeImage*/Leading->StreamHeader->DataUsed, TRUE ); } else { KeDelay(33); KsStreamPointerUnlock(Leading, FALSE); Status = STATUS_BUFFER_OVERFLOW; } } // // Turn Off the PinGate to avoid processing // PKSGATE pGate = KsPinGetAndGate(m_Pin); if (pGate) { KsGateTurnInputOff(pGate); } KsPinReleaseProcessingMutex(m_Pin); SnPrint(DEBUGLVL_VERBOSE, ("Leave CStillPin::Process (0x%X)\n",Status)); return Status; }
NTSTATUS CEncoderPin:: Process ( ) /*++ Routine Description: The process dispatch for the pin bridges to this location. We handle setting up scatter gather mappings, etc... Arguments: None Return Value: Success / Failure --*/ { PAGED_CODE(); NTSTATUS Status = STATUS_SUCCESS; PKSSTREAM_POINTER Leading; Leading = KsPinGetLeadingEdgeStreamPointer ( m_Pin, KSSTREAM_POINTER_STATE_LOCKED ); while (NT_SUCCESS (Status) && Leading) { PKSSTREAM_POINTER ClonePointer; PSTREAM_POINTER_CONTEXT SPContext; // // For optimization sake in this particular sample, I will only keep // one clone stream pointer per frame. This complicates the logic // here but simplifies the completions. // // I'm also choosing to do this since I need to keep track of the // virtual addresses corresponding to each mapping since I'm faking // DMA. It simplifies that too. // if (!m_PreviousStreamPointer) { // // First thing we need to do is clone the leading edge. This allows // us to keep reference on the frames while they're in DMA. // Status = KsStreamPointerClone ( Leading, NULL, sizeof (STREAM_POINTER_CONTEXT), &ClonePointer ); // // I use this for easy chunking of the buffer. We're not really // dealing with physical addresses. This keeps track of what // virtual address in the buffer the current scatter / gather // mapping corresponds to for the fake hardware. // if (NT_SUCCESS (Status)) { // // Set the stream header data used to 0. We update this // in the DMA completions. For queues with DMA, we must // update this field ourselves. // ClonePointer -> StreamHeader -> DataUsed = 0; SPContext = reinterpret_cast <PSTREAM_POINTER_CONTEXT> (ClonePointer -> Context); SPContext -> BufferVirtual = reinterpret_cast <PUCHAR> ( ClonePointer -> StreamHeader -> Data ); } else { SPContext = NULL; } } else { ClonePointer = m_PreviousStreamPointer; SPContext = reinterpret_cast <PSTREAM_POINTER_CONTEXT> (ClonePointer -> Context); Status = STATUS_SUCCESS; } // // If the clone failed, likely we're out of resources. Break out // of the loop for now. We may end up starving DMA. // if (!NT_SUCCESS (Status) || SPContext == NULL) { KsStreamPointerUnlock (Leading, FALSE); break; } // // Program the fake hardware. I would use Clone -> OffsetOut.*, but // because of the optimization of one stream pointer per frame, it // doesn't make complete sense. // ULONG MappingsUsed = m_Device -> ProgramScatterGatherMappings ( &(SPContext -> BufferVirtual), Leading -> OffsetOut.Mappings, Leading -> OffsetOut.Remaining ); // // In order to keep one clone per frame and simplify the fake DMA // logic, make a check to see if we completely used the mappings in // the leading edge. Set a flag. // if (MappingsUsed == Leading -> OffsetOut.Remaining) { m_PreviousStreamPointer = NULL; } else { m_PreviousStreamPointer = ClonePointer; } if (MappingsUsed) { // // If any mappings were added to scatter / gather queues, // advance the leading edge by that number of mappings. If // we run off the end of the queue, Status will be // STATUS_DEVICE_NOT_READY. Otherwise, the leading edge will // point to a new frame. The previous one will not have been // dismissed (unless "DMA" completed) since there's a clone // pointer referencing the frames. // Status = KsStreamPointerAdvanceOffsets ( Leading, 0, MappingsUsed, FALSE ); } else { // // The hardware was incapable of adding more entries. The S/G // table is full. // Status = STATUS_PENDING; break; } } // // If the leading edge failed to lock (this is always possible, remember // that locking CAN occassionally fail), don't blow up passing NULL // into KsStreamPointerUnlock. Also, set m_PendIo to kick us later... // if (!Leading) { m_PendIo = TRUE; // // If the lock failed, there's no point in getting called back // immediately. The lock could fail due to insufficient memory, // etc... In this case, we don't want to get called back immediately. // Return pending. The m_PendIo flag will cause us to get kicked // later. // Status = STATUS_PENDING; } // // If we didn't run the leading edge off the end of the queue, unlock it. // if (NT_SUCCESS (Status) && Leading) { KsStreamPointerUnlock (Leading, FALSE); } else { // // DEVICE_NOT_READY indicates that the advancement ran off the end // of the queue. We couldn't lock the leading edge. // if (Status == STATUS_DEVICE_NOT_READY) Status = STATUS_SUCCESS; } // // If we failed with something that requires pending, set the pending I/O // flag so we know we need to start it again in a completion DPC. // if (!NT_SUCCESS (Status) || Status == STATUS_PENDING) { m_PendIo = TRUE; } return Status; }