mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 19:47:27 +00:00
quartz: Generate a seek table for the mpeg splitter.
Speeds up seeking mp3's on large files.
This commit is contained in:
parent
55f3ba9dc0
commit
24cac935f0
|
@ -52,6 +52,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
|
||||||
#define MPEG_AUDIO_HEADER 1
|
#define MPEG_AUDIO_HEADER 1
|
||||||
#define MPEG_NO_HEADER 0
|
#define MPEG_NO_HEADER 0
|
||||||
|
|
||||||
|
#define SEEK_INTERVAL (ULONGLONG)(30 * 10000000) /* Add an entry every 30 seconds */
|
||||||
|
|
||||||
|
struct seek_entry {
|
||||||
|
ULONGLONG bytepos;
|
||||||
|
ULONGLONG timepos;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct MPEGSplitterImpl
|
typedef struct MPEGSplitterImpl
|
||||||
{
|
{
|
||||||
ParserImpl Parser;
|
ParserImpl Parser;
|
||||||
|
@ -63,6 +70,8 @@ typedef struct MPEGSplitterImpl
|
||||||
DWORD header_bytes;
|
DWORD header_bytes;
|
||||||
DWORD remaining_bytes;
|
DWORD remaining_bytes;
|
||||||
BOOL seek;
|
BOOL seek;
|
||||||
|
ULONG seek_entries;
|
||||||
|
struct seek_entry *seektable;
|
||||||
} MPEGSplitterImpl;
|
} MPEGSplitterImpl;
|
||||||
|
|
||||||
static int MPEGSplitter_head_check(const BYTE *header)
|
static int MPEGSplitter_head_check(const BYTE *header)
|
||||||
|
@ -649,11 +658,16 @@ static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin)
|
||||||
This->header_bytes = pos;
|
This->header_bytes = pos;
|
||||||
This->skipbytes = 0;
|
This->skipbytes = 0;
|
||||||
|
|
||||||
|
This->seektable[0].bytepos = pos;
|
||||||
|
This->seektable[0].timepos = 0;
|
||||||
|
|
||||||
switch(streamtype)
|
switch(streamtype)
|
||||||
{
|
{
|
||||||
case MPEG_AUDIO_HEADER:
|
case MPEG_AUDIO_HEADER:
|
||||||
{
|
{
|
||||||
LONGLONG duration = 0;
|
LONGLONG duration = 0;
|
||||||
|
DWORD last_entry = 0;
|
||||||
|
|
||||||
DWORD ticks = GetTickCount();
|
DWORD ticks = GetTickCount();
|
||||||
|
|
||||||
hr = MPEGSplitter_init_audio(This, header, &piOutput, &amt);
|
hr = MPEGSplitter_init_audio(This, header, &piOutput, &amt);
|
||||||
|
@ -703,6 +717,25 @@ static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pos += length;
|
pos += length;
|
||||||
|
|
||||||
|
if (This->seektable && (duration / SEEK_INTERVAL) > last_entry)
|
||||||
|
{
|
||||||
|
if (last_entry + 1 > duration / SEEK_INTERVAL)
|
||||||
|
{
|
||||||
|
ERR("Somehow skipped %d interval lengths instead of 1\n", (DWORD)(duration/SEEK_INTERVAL) - (last_entry + 1));
|
||||||
|
}
|
||||||
|
++last_entry;
|
||||||
|
|
||||||
|
TRACE("Entry: %u\n", last_entry);
|
||||||
|
if (last_entry >= This->seek_entries)
|
||||||
|
{
|
||||||
|
This->seek_entries += 64;
|
||||||
|
This->seektable = CoTaskMemRealloc(This->seektable, (This->seek_entries)*sizeof(struct seek_entry));
|
||||||
|
}
|
||||||
|
This->seektable[last_entry].bytepos = pos;
|
||||||
|
This->seektable[last_entry].timepos = duration;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(pos >> 32), (DWORD)pos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
|
TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(pos >> 32), (DWORD)pos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
|
||||||
}
|
}
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
|
@ -751,11 +784,6 @@ static HRESULT MPEGSplitter_seek(IBaseFilter *iface)
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
BYTE header[4];
|
BYTE header[4];
|
||||||
|
|
||||||
/* Position, in bytes */
|
|
||||||
bytepos = This->header_bytes;
|
|
||||||
|
|
||||||
/* Position, in media time, current and new */
|
|
||||||
timepos = 0;
|
|
||||||
newpos = This->Parser.mediaSeeking.llCurrent;
|
newpos = This->Parser.mediaSeeking.llCurrent;
|
||||||
|
|
||||||
if (newpos > This->duration)
|
if (newpos > This->duration)
|
||||||
|
@ -770,23 +798,28 @@ static HRESULT MPEGSplitter_seek(IBaseFilter *iface)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position, cached */
|
||||||
|
bytepos = This->seektable[newpos / SEEK_INTERVAL].bytepos;
|
||||||
|
timepos = This->seektable[newpos / SEEK_INTERVAL].timepos;
|
||||||
|
|
||||||
hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
|
hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
|
||||||
while (bytepos < This->EndOfFile && SUCCEEDED(hr))
|
while (timepos < newpos && bytepos + 3 < This->EndOfFile)
|
||||||
{
|
{
|
||||||
LONGLONG length = 0;
|
LONGLONG length = 0;
|
||||||
hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
|
hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
|
||||||
while (parse_header(header, &length, &timepos))
|
if (hr != S_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
while (parse_header(header, &length, &timepos) && bytepos + 3 < This->EndOfFile)
|
||||||
{
|
{
|
||||||
/* No valid header yet; shift by a byte and check again */
|
/* No valid header yet; shift by a byte and check again */
|
||||||
memmove(header, header+1, 3);
|
memmove(header, header+1, 3);
|
||||||
hr = IAsyncReader_SyncRead(pPin->pReader, ++bytepos, 1, header + 3);
|
hr = IAsyncReader_SyncRead(pPin->pReader, ++bytepos, 1, header + 3);
|
||||||
if (FAILED(hr))
|
if (hr != S_OK)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bytepos += length;
|
bytepos += length;
|
||||||
TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(bytepos >> 32), (DWORD)bytepos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
|
TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(bytepos >> 32), (DWORD)bytepos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
|
||||||
if (timepos >= newpos)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
|
@ -836,6 +869,14 @@ HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
ZeroMemory(This, sizeof(MPEGSplitterImpl));
|
ZeroMemory(This, sizeof(MPEGSplitterImpl));
|
||||||
|
This->seektable = CoTaskMemAlloc(sizeof(struct seek_entry) * 64);
|
||||||
|
if (!This->seektable)
|
||||||
|
{
|
||||||
|
CoTaskMemFree(This);
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
This->seek_entries = 64;
|
||||||
|
|
||||||
hr = Parser_Create(&(This->Parser), &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, NULL, MPEGSplitter_seek, NULL);
|
hr = Parser_Create(&(This->Parser), &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, NULL, MPEGSplitter_seek, NULL);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue