quartz: Implement VideoRenderer_GetCurrentImage.
authorMaarten Lankhorst <m.b.lankhorst@gmail.com>
Tue, 10 Jun 2008 16:45:25 +0000 (18:45 +0200)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 24 Jun 2008 09:47:10 +0000 (11:47 +0200)
dlls/quartz/videorenderer.c

index fa3905e12b930a937cb51a3d15c1fad593cd48a8..bda9fdf59133ee62fc56beb4d9150f3c3fda4904 100644 (file)
@@ -87,6 +87,9 @@ typedef struct VideoRendererImpl
     BOOL bAggregatable;
     REFERENCE_TIME rtLastStop;
     MediaSeekingImpl mediaSeeking;
+
+    /* During pause we can hold a single sample, for use in GetCurrentImage */
+    IMediaSample *sample_held;
 } VideoRendererImpl;
 
 static LRESULT CALLBACK VideoWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@@ -408,6 +411,15 @@ static HRESULT VideoRenderer_Sample(LPVOID iface, IMediaSample * pSample)
     }
 #endif
 
+    if (This->state == State_Paused)
+    {
+        if (This->sample_held)
+            IMediaSample_Release(This->sample_held);
+
+        This->sample_held = pSample;
+        IMediaSample_AddRef(pSample);
+    }
+
     if (This->pClock && This->state == State_Running)
     {
         REFERENCE_TIME time, trefstart, trefstop;
@@ -585,6 +597,7 @@ HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
         MediaSeekingImpl_Init((IBaseFilter*)pVideoRenderer, VideoRendererImpl_Change, VideoRendererImpl_Change, VideoRendererImpl_Change, &pVideoRenderer->mediaSeeking, &pVideoRenderer->csFilter);
         pVideoRenderer->mediaSeeking.lpVtbl = &VideoRendererImpl_Seeking_Vtbl;
 
+        pVideoRenderer->sample_held = NULL;
         *ppv = (LPVOID)pVideoRenderer;
     }
     else
@@ -774,9 +787,15 @@ static HRESULT WINAPI VideoRenderer_Stop(IBaseFilter * iface)
     EnterCriticalSection(&This->csFilter);
     {
         This->state = State_Stopped;
+
+        if (This->sample_held)
+        {
+            IMediaSample_Release(This->sample_held);
+            This->sample_held = NULL;
+        }
     }
     LeaveCriticalSection(&This->csFilter);
-    
+
     return S_OK;
 }
 
@@ -812,6 +831,12 @@ static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tSta
 
         This->rtStreamStart = tStart;
         This->state = State_Running;
+
+        if (This->sample_held)
+        {
+            IMediaSample_Release(This->sample_held);
+            This->sample_held = NULL;
+        }
     }
     LeaveCriticalSection(&This->csFilter);
 
@@ -1438,8 +1463,59 @@ static HRESULT WINAPI Basicvideo_GetCurrentImage(IBasicVideo *iface,
                                                 long *pBufferSize,
                                                 long *pDIBImage) {
     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
+    BITMAPINFOHEADER *bmiHeader;
+    LONG needed_size;
+    AM_MEDIA_TYPE *amt = &This->pInputPin->pin.mtCurrent;
+    char *ptr;
+
+    EnterCriticalSection(&This->csFilter);
+
+    if (!This->sample_held)
+    {
+         LeaveCriticalSection(&This->csFilter);
+         return (This->state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
+    }
+
+    FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage);
 
-    FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pBufferSize, pDIBImage);
+    if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
+    {
+        bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
+    }
+    else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
+    {
+        bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
+    }
+    else
+    {
+        FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
+        LeaveCriticalSection(&This->csFilter);
+        return VFW_E_RUNTIME_ERROR;
+    }
+
+    needed_size = bmiHeader->biSize;
+    needed_size += IMediaSample_GetActualDataLength(This->sample_held);
+
+    if (!pDIBImage)
+    {
+        *pBufferSize = needed_size;
+        LeaveCriticalSection(&This->csFilter);
+        return S_OK;
+    }
+
+    if (needed_size < *pBufferSize)
+    {
+        ERR("Buffer too small %u/%lu\n", needed_size, *pBufferSize);
+        LeaveCriticalSection(&This->csFilter);
+        return E_FAIL;
+    }
+    *pBufferSize = needed_size;
+
+    memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
+    IMediaSample_GetPointer(This->sample_held, (BYTE **)&ptr);
+    memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(This->sample_held));
+
+    LeaveCriticalSection(&This->csFilter);
 
     return S_OK;
 }