Commit b1b75243 authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Alexandre Julliard

quartz: Prepare mpeg splitter code for seeking by making most splitter parsing locked.

parent 0e9ed6b4
...@@ -60,7 +60,9 @@ typedef struct MPEGSplitterImpl ...@@ -60,7 +60,9 @@ typedef struct MPEGSplitterImpl
LONGLONG duration; LONGLONG duration;
LONGLONG position; LONGLONG position;
DWORD skipbytes; DWORD skipbytes;
DWORD header_bytes;
DWORD remaining_bytes; DWORD remaining_bytes;
BOOL seek;
} MPEGSplitterImpl; } MPEGSplitterImpl;
static int MPEGSplitter_head_check(const BYTE *header) static int MPEGSplitter_head_check(const BYTE *header)
...@@ -115,7 +117,7 @@ static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration) ...@@ -115,7 +117,7 @@ static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration)
((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf && ((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf &&
((header[2]>>2)&0x3) != 0x3)) ((header[2]>>2)&0x3) != 0x3))
{ {
WARN("Not a valid header: %02x:%02x\n", header[0], header[1]); FIXME("Not a valid header: %02x:%02x\n", header[0], header[1]);
return E_INVALIDARG; return E_INVALIDARG;
} }
...@@ -132,6 +134,13 @@ static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration) ...@@ -132,6 +134,13 @@ static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration)
emphasis = ((header[3]>>0)&0x3); emphasis = ((header[3]>>0)&0x3);
bitrate = tabsel_123[lsf][layer-1][bitrate_index] * 1000; bitrate = tabsel_123[lsf][layer-1][bitrate_index] * 1000;
if (!bitrate || layer != 3)
{
ERR("Not a valid header: %02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3]);
return E_INVALIDARG;
}
if (layer == 3 || layer == 2) if (layer == 3 || layer == 2)
length = 144 * bitrate / freqs[freq_index] + padding; length = 144 * bitrate / freqs[freq_index] + padding;
else else
...@@ -173,7 +182,7 @@ static HRESULT copy_data(IMediaSample *to, BYTE** from, DWORD *flen, DWORD amoun ...@@ -173,7 +182,7 @@ static HRESULT copy_data(IMediaSample *to, BYTE** from, DWORD *flen, DWORD amoun
return hr; return hr;
} }
static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen) static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen, IMediaSample *pCurrentSample)
{ {
Parser_OutputPin * pOutputPin = (Parser_OutputPin*)This->Parser.ppPins[1]; Parser_OutputPin * pOutputPin = (Parser_OutputPin*)This->Parser.ppPins[1];
LONGLONG length = 0; LONGLONG length = 0;
...@@ -197,11 +206,11 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen) ...@@ -197,11 +206,11 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen)
{ {
DWORD towrite = min(This->remaining_bytes, *flen); DWORD towrite = min(This->remaining_bytes, *flen);
hr = copy_data(This->pCurrentSample, fbuf, flen, towrite); hr = copy_data(pCurrentSample, fbuf, flen, towrite);
if (FAILED(hr)) if (FAILED(hr))
{ {
WARN("Could not resize sample: %08x\n", hr); WARN("Could not resize sample: %08x\n", hr);
goto release; return hr;
} }
This->remaining_bytes -= towrite; This->remaining_bytes -= towrite;
...@@ -213,7 +222,7 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen) ...@@ -213,7 +222,7 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen)
} }
/* Special case, last source sample might (or might not have) had a header, and now we want to retrieve it */ /* Special case, last source sample might (or might not have) had a header, and now we want to retrieve it */
dlen = IMediaSample_GetActualDataLength(This->pCurrentSample); dlen = IMediaSample_GetActualDataLength(pCurrentSample);
if (dlen > 0 && dlen < 4) if (dlen > 0 && dlen < 4)
{ {
BYTE *header = NULL; BYTE *header = NULL;
...@@ -222,15 +231,15 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen) ...@@ -222,15 +231,15 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen)
/* Shoot anyone with a small sample! */ /* Shoot anyone with a small sample! */
assert(*flen >= 6); assert(*flen >= 6);
hr = IMediaSample_GetPointer(This->pCurrentSample, &header); hr = IMediaSample_GetPointer(pCurrentSample, &header);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
hr = IMediaSample_SetActualDataLength(This->pCurrentSample, 7); hr = IMediaSample_SetActualDataLength(pCurrentSample, 7);
if (FAILED(hr)) if (FAILED(hr))
{ {
WARN("Could not resize sample: %08x\n", hr); WARN("Could not resize sample: %08x\n", hr);
goto release; return hr;
} }
memcpy(header + dlen, *fbuf, 6 - dlen); memcpy(header + dlen, *fbuf, 6 - dlen);
...@@ -243,12 +252,12 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen) ...@@ -243,12 +252,12 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen)
/* No header found */ /* No header found */
if (attempts == dlen) if (attempts == dlen)
{ {
hr = IMediaSample_SetActualDataLength(This->pCurrentSample, 0); hr = IMediaSample_SetActualDataLength(pCurrentSample, 0);
return hr; return hr;
} }
IMediaSample_SetActualDataLength(This->pCurrentSample, 4); IMediaSample_SetActualDataLength(pCurrentSample, 4);
IMediaSample_SetTime(This->pCurrentSample, &time, &This->position); IMediaSample_SetTime(pCurrentSample, &time, &This->position);
/* Move header back to beginning */ /* Move header back to beginning */
if (attempts) if (attempts)
...@@ -274,21 +283,21 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen) ...@@ -274,21 +283,21 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, BYTE** fbuf, DWORD *flen)
if (*flen < 4) if (*flen < 4)
{ {
assert(!length); assert(!length);
hr = copy_data(This->pCurrentSample, fbuf, flen, *flen); hr = copy_data(pCurrentSample, fbuf, flen, *flen);
return hr; return hr;
} }
IMediaSample_SetTime(This->pCurrentSample, &time, &This->position); IMediaSample_SetTime(pCurrentSample, &time, &This->position);
if (*flen < length) if (*flen < length)
{ {
/* Partial copy: Copy 4 bytes, the rest will be copied by the logic for This->remaining_bytes */ /* Partial copy: Copy 4 bytes, the rest will be copied by the logic for This->remaining_bytes */
This->remaining_bytes = length - 4; This->remaining_bytes = length - 4;
copy_data(This->pCurrentSample, fbuf, flen, 4); copy_data(pCurrentSample, fbuf, flen, 4);
return hr; return hr;
} }
hr = copy_data(This->pCurrentSample, fbuf, flen, length); hr = copy_data(pCurrentSample, fbuf, flen, length);
if (FAILED(hr)) if (FAILED(hr))
{ {
WARN("Couldn't set data size to %x%08x\n", (DWORD)(length >> 32), (DWORD)length); WARN("Couldn't set data size to %x%08x\n", (DWORD)(length >> 32), (DWORD)length);
...@@ -306,21 +315,33 @@ out_append: ...@@ -306,21 +315,33 @@ out_append:
if (length > *flen) if (length > *flen)
break; break;
if (FAILED(copy_data(This->pCurrentSample, fbuf, flen, length))) if (FAILED(copy_data(pCurrentSample, fbuf, flen, length)))
break; break;
This->position += sampleduration; This->position += sampleduration;
sampleduration = 0; sampleduration = 0;
IMediaSample_SetTime(This->pCurrentSample, &time, &This->position); IMediaSample_SetTime(pCurrentSample, &time, &This->position);
} }
TRACE("Media time: %u.%03u\n", (DWORD)(This->position/10000000), (DWORD)((This->position/10000)%1000)); TRACE("Media time: %u.%03u\n", (DWORD)(This->position/10000000), (DWORD)((This->position/10000)%1000));
hr = OutputPin_SendSample(&pOutputPin->pin, This->pCurrentSample); IMediaSample_AddRef(pCurrentSample);
LeaveCriticalSection(&This->Parser.csFilter);
hr = OutputPin_SendSample(&pOutputPin->pin, pCurrentSample);
EnterCriticalSection(&This->Parser.csFilter);
IMediaSample_Release(pCurrentSample);
if (FAILED(hr)) if (FAILED(hr))
{
WARN("Error sending sample (%x)\n", hr); WARN("Error sending sample (%x)\n", hr);
release: return hr;
IMediaSample_Release(This->pCurrentSample); }
This->pCurrentSample = NULL; if (This->pCurrentSample)
{
IMediaSample_Release(pCurrentSample);
This->pCurrentSample = NULL;
}
return hr; return hr;
} }
...@@ -346,6 +367,7 @@ static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample * pSample) ...@@ -346,6 +367,7 @@ static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample * pSample)
/* trace removed for performance reasons */ /* trace removed for performance reasons */
/* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */ /* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */
EnterCriticalSection(&This->Parser.csFilter);
/* Now, try to find a new header */ /* Now, try to find a new header */
while (cbSrcStream > 0) while (cbSrcStream > 0)
{ {
...@@ -361,16 +383,16 @@ static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample * pSample) ...@@ -361,16 +383,16 @@ static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample * pSample)
if (FAILED(hr = IMediaSample_SetActualDataLength(This->pCurrentSample, 0))) if (FAILED(hr = IMediaSample_SetActualDataLength(This->pCurrentSample, 0)))
goto fail; goto fail;
IMediaSample_SetSyncPoint(This->pCurrentSample, TRUE); IMediaSample_SetSyncPoint(This->pCurrentSample, TRUE);
IMediaSample_SetDiscontinuity(This->pCurrentSample, This->seek);
This->seek = FALSE;
} }
hr = FillBuffer(This, &pbSrcStream, &cbSrcStream); hr = FillBuffer(This, &pbSrcStream, &cbSrcStream, This->pCurrentSample);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr) && hr != S_FALSE)
if (hr == S_FALSE)
break;
continue; continue;
}
fail: fail:
FIXME("Failed with hres: %08x!\n", hr); if (hr != S_FALSE)
FIXME("Failed with hres: %08x!\n", hr);
This->skipbytes += This->remaining_bytes; This->skipbytes += This->remaining_bytes;
This->remaining_bytes = 0; This->remaining_bytes = 0;
if (This->pCurrentSample) if (This->pCurrentSample)
...@@ -379,6 +401,7 @@ fail: ...@@ -379,6 +401,7 @@ fail:
IMediaSample_Release(This->pCurrentSample); IMediaSample_Release(This->pCurrentSample);
This->pCurrentSample = NULL; This->pCurrentSample = NULL;
} }
break;
} }
if (BYTES_FROM_MEDIATIME(tStop) >= This->EndOfFile) if (BYTES_FROM_MEDIATIME(tStop) >= This->EndOfFile)
...@@ -416,6 +439,7 @@ fail: ...@@ -416,6 +439,7 @@ fail:
hr = S_FALSE; hr = S_FALSE;
} }
LeaveCriticalSection(&This->Parser.csFilter);
return hr; return hr;
} }
...@@ -612,7 +636,7 @@ static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin) ...@@ -612,7 +636,7 @@ static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin)
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
pos -= 4; pos -= 4;
This->skipbytes = pos; This->header_bytes = This->skipbytes = pos;
switch(streamtype) switch(streamtype)
{ {
...@@ -671,6 +695,7 @@ static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin) ...@@ -671,6 +695,7 @@ static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin)
hr = S_OK; hr = S_OK;
TRACE("Duration: %d seconds\n", (DWORD)(duration / 10000000)); TRACE("Duration: %d seconds\n", (DWORD)(duration / 10000000));
TRACE("Parsing took %u ms\n", GetTickCount() - ticks); TRACE("Parsing took %u ms\n", GetTickCount() - ticks);
This->duration = duration;
break; break;
} }
case MPEG_VIDEO_HEADER: case MPEG_VIDEO_HEADER:
...@@ -701,9 +726,18 @@ static HRESULT MPEGSplitter_cleanup(LPVOID iface) ...@@ -701,9 +726,18 @@ static HRESULT MPEGSplitter_cleanup(LPVOID iface)
IMediaSample_Release(This->pCurrentSample); IMediaSample_Release(This->pCurrentSample);
This->pCurrentSample = NULL; This->pCurrentSample = NULL;
if (This->Parser.pInputPin && !This->seek)
{
This->skipbytes += This->remaining_bytes;
This->Parser.pInputPin->rtCurrent += MEDIATIME_FROM_BYTES(This->skipbytes);
}
if (!This->seek)
This->skipbytes = This->remaining_bytes = 0;
return S_OK; return S_OK;
} }
HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv) HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
{ {
MPEGSplitterImpl *This; MPEGSplitterImpl *This;
...@@ -727,6 +761,7 @@ HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv) ...@@ -727,6 +761,7 @@ HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
CoTaskMemFree(This); CoTaskMemFree(This);
return hr; return hr;
} }
This->seek = TRUE;
/* Note: This memory is managed by the parser filter once created */ /* Note: This memory is managed by the parser filter once created */
*ppv = (LPVOID)This; *ppv = (LPVOID)This;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment