[KSPROXY]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 15 Mar 2010 13:11:31 +0000 (13:11 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 15 Mar 2010 13:11:31 +0000 (13:11 +0000)
- Implement ISpecifyPropertyPages interface for CInputPin
- Implement IKsInterfaceHandler::KsSetPin, IKsInterfaceHandler::KsProcessMediaSamples, IKsInterfaceHandler::KsCompleteIo

svn path=/trunk/; revision=46205

reactos/dll/directx/ksproxy/input_pin.cpp
reactos/dll/directx/ksproxy/interface.cpp
reactos/dll/directx/ksproxy/precomp.h

index 857b3cc..e922b2e 100644 (file)
@@ -52,11 +52,11 @@ class CInputPin : public IPin,
                   public IKsControl,
                   public IKsObject,
                   public IKsPinEx,
-                  public IMemInputPin
+                  public IMemInputPin,
+                  public ISpecifyPropertyPages
 /*
                   public IQualityControl,
                   public IKsPinPipe,
-                  public ISpecifyPropertyPages,
                   public IStreamBuilder,
                   public IKsPinFactory,
                   public IKsAggregateControl
@@ -98,6 +98,9 @@ public:
     HRESULT STDMETHODCALLTYPE EndFlush();
     HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
 
+    // ISpecifyPropertyPages
+    HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages);
+
     //IKsObject methods
     HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
 
@@ -205,7 +208,12 @@ CInputPin::QueryInterface(
         reinterpret_cast<IKsPinEx*>(*Output)->AddRef();
         return NOERROR;
     }
-
+    else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages))
+    {
+        *Output = (ISpecifyPropertyPages*)(this);
+        reinterpret_cast<ISpecifyPropertyPages*>(*Output)->AddRef();
+        return NOERROR;
+    }
 
     WCHAR Buffer[MAX_PATH];
     LPOLESTR lpstr;
@@ -217,6 +225,23 @@ CInputPin::QueryInterface(
     return E_NOINTERFACE;
 }
 
+//-------------------------------------------------------------------
+// ISpecifyPropertyPages
+//
+
+HRESULT
+STDMETHODCALLTYPE
+CInputPin::GetPages(CAUUID *pPages)
+{
+    if (!pPages)
+        return E_POINTER;
+
+    pPages->cElems = 0;
+    pPages->pElems = NULL;
+
+    return S_OK;
+}
+
 //-------------------------------------------------------------------
 // IMemInputPin
 //
index 4289cd1..7b6b0d9 100644 (file)
@@ -35,14 +35,27 @@ public:
     HRESULT STDMETHODCALLTYPE KsProcessMediaSamples(IKsDataTypeHandler *KsDataTypeHandler, IMediaSample** SampleList, PLONG SampleCount, KSIOOPERATION IoOperation, PKSSTREAM_SEGMENT *StreamSegment);
     HRESULT STDMETHODCALLTYPE KsCompleteIo(PKSSTREAM_SEGMENT StreamSegment);
 
-    CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL){};
+    CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL), m_Pin(0){};
     virtual ~CKsInterfaceHandler(){};
 
 protected:
     LONG m_Ref;
     HANDLE m_Handle;
+    IKsPinEx * m_Pin;
 };
 
+typedef struct
+{
+    KSSTREAM_SEGMENT StreamSegment;
+    IMediaSample * MediaSample[64];
+
+    ULONG SampleCount;
+    ULONG ExtendedSize;
+    PKSSTREAM_HEADER StreamHeader;
+    OVERLAPPED Overlapped;
+}KSSTREAM_SEGMENT_EXT, *PKSSTREAM_SEGMENT_EXT;
+
+
 HRESULT
 STDMETHODCALLTYPE
 CKsInterfaceHandler::QueryInterface(
@@ -66,22 +79,43 @@ CKsInterfaceHandler::KsSetPin(
 {
     HRESULT hr;
     IKsObject * KsObject;
+    IKsPinEx * Pin;
 
-    // check if IKsObject is supported
-    hr = KsPin->QueryInterface(IID_IKsObject, (void**)&KsObject);
-
+    // get IKsPinEx interface
+    hr = KsPin->QueryInterface(IID_IKsPinEx, (void**)&Pin);
     if (SUCCEEDED(hr))
     {
-        // get pin handle
-        m_Handle = KsObject->KsGetObjectHandle();
+        // check if IKsObject is supported
+        hr = KsPin->QueryInterface(IID_IKsObject, (void**)&KsObject);
+
+        if (SUCCEEDED(hr))
+        {
+            // get pin handle
+            m_Handle = KsObject->KsGetObjectHandle();
 
-        // release IKsObject interface
-        KsObject->Release();
+            // release IKsObject interface
+            KsObject->Release();
 
-        if (!m_Handle)
+            if (!m_Handle)
+            {
+                // expected a file handle
+                hr = E_UNEXPECTED;
+                Pin->Release();
+            }
+            else
+            {
+                if (m_Pin)
+                {
+                    // release old interface
+                    m_Pin->Release();
+                }
+                m_Pin = Pin;
+            }
+        }
+        else
         {
-            // expected a file handle
-            return E_UNEXPECTED;
+            //release IKsPinEx interface
+            Pin->Release();
         }
     }
 
@@ -96,19 +130,333 @@ CKsInterfaceHandler::KsProcessMediaSamples(
      IMediaSample** SampleList,
      PLONG SampleCount,
      KSIOOPERATION IoOperation,
-     PKSSTREAM_SEGMENT *StreamSegment)
+     PKSSTREAM_SEGMENT *OutStreamSegment)
 {
-    OutputDebugString("UNIMPLEMENTED\n");
-    return E_NOTIMPL;
+    PKSSTREAM_SEGMENT_EXT StreamSegment;
+    ULONG ExtendedSize, Index, BytesReturned;
+    HRESULT hr = S_OK;
+
+    OutputDebugString("CKsInterfaceHandler::KsProcessMediaSamples\n");
+
+    // sanity check
+    assert(*SampleCount);
+
+    if (*SampleCount == 0 || *SampleCount < 0)
+        return E_FAIL;
+
+    // zero stream segment
+    *OutStreamSegment = NULL;
+
+    // allocate stream segment
+    StreamSegment = (PKSSTREAM_SEGMENT_EXT)CoTaskMemAlloc(sizeof(KSSTREAM_SEGMENT_EXT));
+    if (!StreamSegment)
+        return E_OUTOFMEMORY;
+
+    // zero stream segment
+    ZeroMemory(StreamSegment, sizeof(KSSTREAM_SEGMENT_EXT));
+
+    //allocate event
+    StreamSegment->StreamSegment.CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+    if (!StreamSegment->StreamSegment.CompletionEvent)
+    {
+        // failed to create event
+        CoTaskMemFree(StreamSegment);
+        return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
+    }
+
+    // increase our own reference count
+    AddRef();
+
+    // setup stream segment
+    StreamSegment->StreamSegment.KsDataTypeHandler = KsDataTypeHandler;
+    StreamSegment->StreamSegment.KsInterfaceHandler = (IKsInterfaceHandler*)this;
+    StreamSegment->StreamSegment.IoOperation = IoOperation;
+    StreamSegment->Overlapped.hEvent = StreamSegment->StreamSegment.CompletionEvent;
+
+
+    // ge extension size
+    ExtendedSize = 0;
+    if (KsDataTypeHandler)
+    {
+        // query extension size
+        KsDataTypeHandler->KsQueryExtendedSize(&ExtendedSize);
+
+        if (ExtendedSize)
+        {
+            // increment reference count
+            KsDataTypeHandler->AddRef();
+        }
+        else
+        {
+            // no need for the datatype handler
+            StreamSegment->StreamSegment.KsDataTypeHandler = NULL;
+        }
+    }
+
+    StreamSegment->ExtendedSize = ExtendedSize;
+    StreamSegment->SampleCount = (ULONG)*SampleCount;
+
+    // calculate stream header size count
+    ULONG StreamHeaderSize = StreamSegment->SampleCount * (sizeof(KSSTREAM_HEADER) + ExtendedSize);
+
+    // allocate stream header
+    StreamSegment->StreamHeader = (PKSSTREAM_HEADER)CoTaskMemAlloc(StreamHeaderSize);
+    if (!StreamSegment->StreamHeader)
+    {
+        // not enough memory
+        CloseHandle(StreamSegment->StreamSegment.CompletionEvent);
+
+        if (StreamSegment->StreamSegment.KsDataTypeHandler)
+            StreamSegment->StreamSegment.KsDataTypeHandler->Release();
+
+        // free stream segment
+        CoTaskMemFree(StreamSegment);
+
+        //release our reference count
+        Release();
+        return E_OUTOFMEMORY;
+    }
+
+    // zero stream headers
+    ZeroMemory(StreamSegment->StreamHeader, StreamHeaderSize);
+
+    PKSSTREAM_HEADER CurStreamHeader = StreamSegment->StreamHeader;
+
+    // initialize all stream headers
+    for(Index = 0; Index < StreamSegment->SampleCount; Index++)
+    {
+         if (ExtendedSize)
+         {
+             // initialize extended size
+             hr = KsDataTypeHandler->KsPrepareIoOperation(SampleList[Index], (CurStreamHeader + 1), IoOperation);
+             // sanity check
+             assert(hr == NOERROR);
+         }
+
+         // query for IMediaSample2 interface
+         IMediaSample2 * MediaSample;
+         AM_SAMPLE2_PROPERTIES Properties;
+
+         hr = SampleList[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample);
+         if (SUCCEEDED(hr))
+         {
+             //get properties
+
+             hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
+
+             //release IMediaSample2 interface
+             MediaSample->Release();
+             if (FAILED(hr))
+                                OutputDebugStringW(L"CKsInterfaceHandler::KsProcessMediaSamples MediaSample::GetProperties failed\n");
+         }
+         else
+         {
+                                OutputDebugStringW(L"CKsInterfaceHandler::KsProcessMediaSamples MediaSample:: only IMediaSample supported\n");
+             // get properties
+             hr = SampleList[Index]->GetPointer((BYTE**)&Properties.pbBuffer);
+             assert(hr == NOERROR);
+             hr = SampleList[Index]->GetTime(&Properties.tStart, &Properties.tStop);
+             assert(hr == NOERROR);
+
+             Properties.dwSampleFlags = 0;
+
+             if (SampleList[Index]->IsDiscontinuity() == S_OK)
+                 Properties.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
+
+             if (SampleList[Index]->IsPreroll() == S_OK)
+                 Properties.dwSampleFlags |= AM_SAMPLE_PREROLL;
+
+             if (SampleList[Index]->IsSyncPoint() == S_OK)
+                 Properties.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
+         }
+
+         WCHAR Buffer[100];
+                swprintf(Buffer, L"BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual);
+         OutputDebugStringW(Buffer);
+
+         CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize;
+         CurStreamHeader->PresentationTime.Denominator = 1;
+         CurStreamHeader->PresentationTime.Numerator = 1;
+         CurStreamHeader->FrameExtent = Properties.cbBuffer;
+         CurStreamHeader->Data = Properties.pbBuffer;
+
+         if (IoOperation == KsIoOperation_Write)
+         {
+             // set flags
+             CurStreamHeader->OptionsFlags = Properties.dwSampleFlags;
+             CurStreamHeader->DataUsed = Properties.lActual;
+             // increment reference count
+             SampleList[Index]->AddRef();
+         }
+
+         // store sample in stream segment
+         StreamSegment->MediaSample[Index] = SampleList[Index];
+
+         // move to next header
+         CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size);
+    }
+
+    // submit to device
+    m_Pin->KsIncrementPendingIoCount();
+
+    if (DeviceIoControl(m_Handle,
+                        IoOperation == KsIoOperation_Write ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM,
+                        NULL, 0,
+                        StreamSegment->StreamHeader,
+                        StreamHeaderSize,
+                        &BytesReturned,
+                        &StreamSegment->Overlapped))
+    {
+        // signal completion
+        SetEvent(StreamSegment->StreamSegment.CompletionEvent);
+        hr = S_OK;
+        *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment;
+    }
+    else
+    {
+        if (GetLastError() == ERROR_IO_PENDING)
+        {
+            *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment;
+            hr = S_OK;
+        }
+    }
+    return hr;
 }
 
 HRESULT
 STDMETHODCALLTYPE
 CKsInterfaceHandler::KsCompleteIo(
-    PKSSTREAM_SEGMENT StreamSegment)
+    PKSSTREAM_SEGMENT InStreamSegment)
 {
-    OutputDebugString("UNIMPLEMENTED\n");
-    return E_NOTIMPL;
+    PKSSTREAM_SEGMENT_EXT StreamSegment;
+    PKSSTREAM_HEADER CurStreamHeader;
+    DWORD dwError = ERROR_SUCCESS, BytesReturned;
+    BOOL bOverlapped;
+    ULONG Index;
+    HRESULT hr;
+    IMediaSample2 * MediaSample;
+    AM_SAMPLE2_PROPERTIES Properties;
+    REFERENCE_TIME Start, Stop;
+
+    OutputDebugStringW(L"CKsInterfaceHandler::KsCompleteIo\n");
+
+    // get private stream segment
+    StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment;
+
+    // get result
+    bOverlapped = GetOverlappedResult(m_Handle, &StreamSegment->Overlapped, &BytesReturned, FALSE);
+    dwError = GetLastError();
+
+    CurStreamHeader = StreamSegment->StreamHeader;
+
+    //iterate through all stream headers
+    for(Index = 0; Index < StreamSegment->SampleCount; Index++)
+    {
+        if (!bOverlapped)
+        {
+            // operation failed
+            m_Pin->KsNotifyError(StreamSegment->MediaSample[Index], MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError));
+        }
+
+        // query IMediaSample2 interface
+        hr = StreamSegment->MediaSample[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample);
+        if (SUCCEEDED(hr))
+        {
+            // media sample properties
+            hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
+            if (SUCCEEDED(hr))
+            {
+                //update media sample properties
+                Properties.dwTypeSpecificFlags = CurStreamHeader->TypeSpecificFlags;
+                Properties.dwSampleFlags |= (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY);
+
+                MediaSample->SetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
+            }
+            // release IMediaSample2 interface
+            MediaSample->Release();
+        }
+
+        // was an extended header used
+        if (StreamSegment->ExtendedSize)
+        {
+            // unprepare stream header extension
+            StreamSegment->StreamSegment.KsDataTypeHandler->KsCompleteIoOperation(StreamSegment->MediaSample[Index], (CurStreamHeader + 1), StreamSegment->StreamSegment.IoOperation, bOverlapped == FALSE);
+        }
+
+        Start = 0;
+        Stop = 0;
+        if (bOverlapped && StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read)
+        {
+            // update common media sample details
+            StreamSegment->MediaSample[Index]->SetSyncPoint((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT));
+            StreamSegment->MediaSample[Index]->SetPreroll((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_PREROLL));
+            StreamSegment->MediaSample[Index]->SetDiscontinuity((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY));
+
+            if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID)
+            {
+                // use valid timestamp
+                Start = CurStreamHeader->PresentationTime.Time;
+
+                if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DURATIONVALID)
+                {
+                    Stop = CurStreamHeader->PresentationTime.Time + CurStreamHeader->Duration;
+                }
+            }
+        }
+
+        // now set time
+        hr = StreamSegment->MediaSample[Index]->SetTime(&Start, &Stop);
+        if (FAILED(hr))
+        {
+            // use start time
+            StreamSegment->MediaSample[Index]->SetTime(&Start, &Start);
+        }
+
+        // set valid data length
+        StreamSegment->MediaSample[Index]->SetActualDataLength(CurStreamHeader->DataUsed);
+
+        if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read)
+        {
+            if (bOverlapped)
+            {
+                // deliver sample
+                m_Pin->KsDeliver(StreamSegment->MediaSample[Index], CurStreamHeader->OptionsFlags);
+            }
+        }
+        else if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Write)
+        {
+            // release media sample reference
+            StreamSegment->MediaSample[Index]->Release();
+        }
+
+        CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size);
+    }
+
+    // delete stream headers
+    CoTaskMemFree(StreamSegment->StreamHeader);
+
+    if (StreamSegment->StreamSegment.KsDataTypeHandler)
+    {
+        // release reference
+        StreamSegment->StreamSegment.KsDataTypeHandler->Release();
+    }
+
+    // decrement pending i/o count
+    m_Pin->KsDecrementPendingIoCount();
+
+    //notify of completion
+    m_Pin->KsMediaSamplesCompleted(InStreamSegment);
+
+    //destroy stream segment
+    CoTaskMemFree(StreamSegment);
+
+    //release reference to ourselves
+    Release();
+
+    // done
+    // Event handle is closed by caller
+    return S_OK;
 }
 
 HRESULT
index 59e2b23..839878e 100644 (file)
@@ -165,3 +165,4 @@ CKsNode_Constructor(
     LPVOID * ppv);
 
 extern const GUID IID_IKsObject;
+extern const GUID IID_IKsPinEx;