secur32: Trace flags as hex values.
[wine] / dlls / quartz / mpegsplit.c
1 /*
2  * MPEG Splitter Filter
3  *
4  * Copyright 2003 Robert Shearman
5  * Copyright 2004-2005 Christian Costa
6  * Copyright 2007 Chris Robinson
7  * Copyright 2008 Maarten Lankhorst
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include <assert.h>
25 #include <math.h>
26
27 #include "quartz_private.h"
28 #include "control_private.h"
29 #include "pin.h"
30
31 #include "uuids.h"
32 #include "mmreg.h"
33 #include "mmsystem.h"
34
35 #include "winternl.h"
36
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
39
40 #include "parser.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
43
44 #define SEQUENCE_HEADER_CODE     0xB3
45 #define PACK_START_CODE          0xBA
46
47 #define SYSTEM_START_CODE        0xBB
48 #define AUDIO_ELEMENTARY_STREAM  0xC0
49 #define VIDEO_ELEMENTARY_STREAM  0xE0
50
51 #define MPEG_SYSTEM_HEADER 3
52 #define MPEG_VIDEO_HEADER 2
53 #define MPEG_AUDIO_HEADER 1
54 #define MPEG_NO_HEADER 0
55
56 #define SEEK_INTERVAL (ULONGLONG)(10 * 10000000) /* Add an entry every 10 seconds */
57
58 struct seek_entry {
59     ULONGLONG bytepos;
60     ULONGLONG timepos;
61 };
62
63 typedef struct MPEGSplitterImpl
64 {
65     ParserImpl Parser;
66     LONGLONG EndOfFile;
67     LONGLONG duration;
68     LONGLONG position;
69     DWORD begin_offset;
70     BYTE header[4];
71
72     /* Whether we just seeked (or started playing) */
73     BOOL seek;
74
75     /* Seeking cache */
76     ULONG seek_entries;
77     struct seek_entry *seektable;
78 } MPEGSplitterImpl;
79
80 static inline MPEGSplitterImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
81 {
82     return (MPEGSplitterImpl *)((char*)iface - FIELD_OFFSET(MPEGSplitterImpl, Parser.sourceSeeking.lpVtbl));
83 }
84
85 static int MPEGSplitter_head_check(const BYTE *header)
86 {
87     /* If this is a possible start code, check for a system or video header */
88     if (header[0] == 0 && header[1] == 0 && header[2] == 1)
89     {
90         /* Check if we got a system or elementary stream start code */
91         if (header[3] == PACK_START_CODE ||
92             header[3] == VIDEO_ELEMENTARY_STREAM ||
93             header[3] == AUDIO_ELEMENTARY_STREAM)
94             return MPEG_SYSTEM_HEADER;
95
96         /* Check for a MPEG video sequence start code */
97         if (header[3] == SEQUENCE_HEADER_CODE)
98             return MPEG_VIDEO_HEADER;
99     }
100
101     /* This should give a good guess if we have an MPEG audio header */
102     if(header[0] == 0xff && ((header[1]>>5)&0x7) == 0x7 &&
103        ((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf &&
104        ((header[2]>>2)&0x3) != 0x3)
105         return MPEG_AUDIO_HEADER;
106
107     /* Nothing yet.. */
108     return MPEG_NO_HEADER;
109 }
110
111 static const WCHAR wszAudioStream[] = {'A','u','d','i','o',0};
112 static const WCHAR wszVideoStream[] = {'V','i','d','e','o',0};
113
114 static const DWORD freqs[10] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000,  8000, 0 };
115
116 static const DWORD tabsel_123[2][3][16] = {
117     { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
118       {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
119       {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
120
121     { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
122       {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
123       {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
124 };
125
126 static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration)
127 {
128     LONGLONG duration;
129
130     int bitrate_index, freq_index, lsf = 1, mpeg1, layer, padding, bitrate, length;
131
132     if (!(header[0] == 0xff && ((header[1]>>5)&0x7) == 0x7 &&
133        ((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf &&
134        ((header[2]>>2)&0x3) != 0x3))
135     {
136         FIXME("Not a valid header: %02x:%02x\n", header[0], header[1]);
137         return E_INVALIDARG;
138     }
139
140     mpeg1 = (header[1]>>4)&0x1;
141     if (mpeg1)
142         lsf = ((header[1]>>3)&0x1)^1;
143
144     layer = 4-((header[1]>>1)&0x3);
145     bitrate_index = ((header[2]>>4)&0xf);
146     freq_index = ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6);
147     padding = ((header[2]>>1)&0x1);
148
149     bitrate = tabsel_123[lsf][layer-1][bitrate_index] * 1000;
150     if (!bitrate || layer != 3)
151     {
152         FIXME("Not a valid header: %02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3]);
153         return E_INVALIDARG;
154     }
155
156
157     if (layer == 3 || layer == 2)
158         length = 144 * bitrate / freqs[freq_index] + padding;
159     else
160         length = 4 * (12 * bitrate / freqs[freq_index] + padding);
161
162     duration = (ULONGLONG)10000000 * (ULONGLONG)(length) / (ULONGLONG)(bitrate/8);
163     *plen = length;
164     if (pduration)
165         *pduration += duration;
166     return S_OK;
167 }
168
169 static HRESULT FillBuffer(MPEGSplitterImpl *This, IMediaSample *pCurrentSample)
170 {
171     Parser_OutputPin * pOutputPin = (Parser_OutputPin*)This->Parser.ppPins[1];
172     LONGLONG length = 0;
173     LONGLONG pos = BYTES_FROM_MEDIATIME(This->Parser.pInputPin->rtNext);
174     LONGLONG time = This->position;
175     HRESULT hr;
176     BYTE *fbuf = NULL;
177     DWORD len = IMediaSample_GetActualDataLength(pCurrentSample);
178
179     TRACE("Source length: %u\n", len);
180     IMediaSample_GetPointer(pCurrentSample, &fbuf);
181
182     /* Find the next valid header.. it <SHOULD> be right here */
183     assert(parse_header(fbuf, &length, &This->position) == S_OK);
184     IMediaSample_SetActualDataLength(pCurrentSample, length);
185
186     /* Queue the next sample */
187     if (length + 4 == len)
188     {
189         PullPin *pin = This->Parser.pInputPin;
190         LONGLONG stop = BYTES_FROM_MEDIATIME(pin->rtStop);
191
192         hr = S_OK;
193         memcpy(This->header, fbuf + length, 4);
194         while (FAILED(hr = parse_header(This->header, &length, NULL)))
195         {
196             memmove(This->header, This->header+1, 3);
197             if (pos + 4 >= stop)
198                 break;
199             IAsyncReader_SyncRead(pin->pReader, ++pos, 1, This->header + 3);
200         }
201         pin->rtNext = MEDIATIME_FROM_BYTES(pos);
202
203         if (SUCCEEDED(hr))
204         {
205             /* Remove 4 for the last header, which should hopefully work */
206             IMediaSample *sample = NULL;
207             LONGLONG rtSampleStart = pin->rtNext - MEDIATIME_FROM_BYTES(4);
208             LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(length + 4);
209
210             if (rtSampleStop > pin->rtStop)
211                 rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
212
213             hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
214             if (SUCCEEDED(hr))
215             {
216                 IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
217                 IMediaSample_SetPreroll(sample, 0);
218                 IMediaSample_SetDiscontinuity(sample, 0);
219                 IMediaSample_SetSyncPoint(sample, 1);
220                 pin->rtCurrent = rtSampleStart;
221                 pin->rtNext = rtSampleStop;
222                 hr = IAsyncReader_Request(pin->pReader, sample, 0);
223             }
224             if (FAILED(hr))
225                 FIXME("o_Ox%08x\n", hr);
226         }
227     }
228     /* If not, we're presumably at the end of file */
229
230     TRACE("Media time : %u.%03u\n", (DWORD)(This->position/10000000), (DWORD)((This->position/10000)%1000));
231
232     IMediaSample_SetTime(pCurrentSample, &time, &This->position);
233
234     hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)&pOutputPin->pin, pCurrentSample);
235
236     if (hr != S_OK)
237     {
238         if (hr != S_FALSE)
239             TRACE("Error sending sample (%x)\n", hr);
240         else
241             TRACE("S_FALSE (%d), holding\n", IMediaSample_GetActualDataLength(pCurrentSample));
242     }
243
244     return hr;
245 }
246
247
248 static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample * pSample, DWORD_PTR cookie)
249 {
250     MPEGSplitterImpl *This = iface;
251     BYTE *pbSrcStream;
252     DWORD cbSrcStream = 0;
253     REFERENCE_TIME tStart, tStop, tAviStart = This->position;
254     HRESULT hr;
255
256     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
257     if (SUCCEEDED(hr))
258     {
259         cbSrcStream = IMediaSample_GetActualDataLength(pSample);
260         hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
261     }
262
263     /* Flush occurring */
264     if (cbSrcStream == 0)
265     {
266         FIXME(".. Why do I need you?\n");
267         return S_OK;
268     }
269
270     /* trace removed for performance reasons */
271     /* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */
272
273     /* Now, try to find a new header */
274     hr = FillBuffer(This, pSample);
275     if (hr != S_OK)
276     {
277         WARN("Failed with hres: %08x!\n", hr);
278
279         /* Unset progression if denied! */
280         if (hr == VFW_E_WRONG_STATE || hr == S_FALSE)
281         {
282             memcpy(This->header, pbSrcStream, 4);
283             This->Parser.pInputPin->rtCurrent = tStart;
284             This->position = tAviStart;
285         }
286     }
287
288     if (BYTES_FROM_MEDIATIME(tStop) >= This->EndOfFile || This->position >= This->Parser.sourceSeeking.llStop)
289     {
290         unsigned int i;
291
292         TRACE("End of file reached\n");
293
294         for (i = 0; i < This->Parser.cStreams; i++)
295         {
296             IPin* ppin;
297
298             hr = IPin_ConnectedTo(This->Parser.ppPins[i+1], &ppin);
299             if (SUCCEEDED(hr))
300             {
301                 hr = IPin_EndOfStream(ppin);
302                 IPin_Release(ppin);
303             }
304             if (FAILED(hr))
305                 WARN("Error sending EndOfStream to pin %u (%x)\n", i, hr);
306         }
307
308         /* Force the pullpin thread to stop */
309         hr = S_FALSE;
310     }
311
312     return hr;
313 }
314
315
316 static HRESULT MPEGSplitter_query_accept(LPVOID iface, const AM_MEDIA_TYPE *pmt)
317 {
318     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
319         return S_FALSE;
320
321     if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Audio))
322         return S_OK;
323
324     if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Video))
325         FIXME("MPEG-1 video streams not yet supported.\n");
326     else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1System))
327         FIXME("MPEG-1 system streams not yet supported.\n");
328     else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1VideoCD))
329         FIXME("MPEG-1 VideoCD streams not yet supported.\n");
330
331     return S_FALSE;
332 }
333
334
335 static HRESULT MPEGSplitter_init_audio(MPEGSplitterImpl *This, const BYTE *header, PIN_INFO *ppiOutput, AM_MEDIA_TYPE *pamt)
336 {
337     WAVEFORMATEX *format;
338     int bitrate_index;
339     int freq_index;
340     int mode_ext;
341     int emphasis;
342     int lsf = 1;
343     int mpeg1;
344     int layer;
345     int mode;
346
347     ZeroMemory(pamt, sizeof(*pamt));
348     ppiOutput->dir = PINDIR_OUTPUT;
349     ppiOutput->pFilter = (IBaseFilter*)This;
350     wsprintfW(ppiOutput->achName, wszAudioStream);
351
352     pamt->formattype = FORMAT_WaveFormatEx;
353     pamt->majortype = MEDIATYPE_Audio;
354     pamt->subtype = MEDIASUBTYPE_MPEG1AudioPayload;
355
356     pamt->lSampleSize = 0;
357     pamt->bFixedSizeSamples = FALSE;
358     pamt->bTemporalCompression = 0;
359
360     mpeg1 = (header[1]>>4)&0x1;
361     if (mpeg1)
362         lsf = ((header[1]>>3)&0x1)^1;
363
364     layer         = 4-((header[1]>>1)&0x3);
365     bitrate_index =   ((header[2]>>4)&0xf);
366     freq_index    =   ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6);
367     mode          =   ((header[3]>>6)&0x3);
368     mode_ext      =   ((header[3]>>4)&0x3);
369     emphasis      =   ((header[3]>>0)&0x3);
370
371     if (!bitrate_index)
372     {
373         /* Set to highest bitrate so samples will fit in for sure */
374         FIXME("Variable-bitrate audio not fully supported.\n");
375         bitrate_index = 15;
376     }
377
378     pamt->cbFormat = ((layer==3)? sizeof(MPEGLAYER3WAVEFORMAT) :
379                                   sizeof(MPEG1WAVEFORMAT));
380     pamt->pbFormat = CoTaskMemAlloc(pamt->cbFormat);
381     if (!pamt->pbFormat)
382         return E_OUTOFMEMORY;
383     ZeroMemory(pamt->pbFormat, pamt->cbFormat);
384     format = (WAVEFORMATEX*)pamt->pbFormat;
385
386     format->wFormatTag      = ((layer == 3) ? WAVE_FORMAT_MPEGLAYER3 :
387                                               WAVE_FORMAT_MPEG);
388     format->nChannels       = ((mode == 3) ? 1 : 2);
389     format->nSamplesPerSec  = freqs[freq_index];
390     format->nAvgBytesPerSec = tabsel_123[lsf][layer-1][bitrate_index] * 1000 / 8;
391
392     if (layer == 3)
393         format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 /
394                               (format->nSamplesPerSec<<lsf) + 1;
395     else if (layer == 2)
396         format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 /
397                               format->nSamplesPerSec + 1;
398     else
399         format->nBlockAlign = 4 * (format->nAvgBytesPerSec * 8 * 12 / format->nSamplesPerSec + 1);
400
401     format->wBitsPerSample = 0;
402
403     if (layer == 3)
404     {
405         MPEGLAYER3WAVEFORMAT *mp3format = (MPEGLAYER3WAVEFORMAT*)format;
406
407         format->cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
408
409         mp3format->wID = MPEGLAYER3_ID_MPEG;
410         mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_ON;
411         mp3format->nBlockSize = format->nBlockAlign;
412         mp3format->nFramesPerBlock = 1;
413
414         /* Beware the evil magic numbers. This struct is apparently horribly
415          * under-documented, and the only references I could find had it being
416          * set to this with no real explanation. It works fine though, so I'm
417          * not complaining (yet).
418          */
419         mp3format->nCodecDelay = 1393;
420     }
421     else
422     {
423         MPEG1WAVEFORMAT *mpgformat = (MPEG1WAVEFORMAT*)format;
424
425         format->cbSize = 22;
426
427         mpgformat->fwHeadLayer   = ((layer == 1) ? ACM_MPEG_LAYER1 :
428                                     ((layer == 2) ? ACM_MPEG_LAYER2 :
429                                      ACM_MPEG_LAYER3));
430         mpgformat->dwHeadBitrate = format->nAvgBytesPerSec * 8;
431         mpgformat->fwHeadMode    = ((mode == 3) ? ACM_MPEG_SINGLECHANNEL :
432                                     ((mode == 2) ? ACM_MPEG_DUALCHANNEL :
433                                      ((mode == 1) ? ACM_MPEG_JOINTSTEREO :
434                                       ACM_MPEG_STEREO)));
435         mpgformat->fwHeadModeExt = ((mode == 1) ? 0x0F : (1<<mode_ext));
436         mpgformat->wHeadEmphasis = emphasis + 1;
437         mpgformat->fwHeadFlags   = ACM_MPEG_ID_MPEG1;
438     }
439     pamt->subtype.Data1 = format->wFormatTag;
440
441     TRACE("MPEG audio stream detected:\n"
442           "\tLayer %d (%#x)\n"
443           "\tFrequency: %d\n"
444           "\tChannels: %d (%d)\n"
445           "\tBytesPerSec: %d\n",
446           layer, format->wFormatTag, format->nSamplesPerSec,
447           format->nChannels, mode, format->nAvgBytesPerSec);
448
449     dump_AM_MEDIA_TYPE(pamt);
450
451     return S_OK;
452 }
453
454
455 static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin, ALLOCATOR_PROPERTIES *props)
456 {
457     PullPin *pPin = (PullPin *)iface;
458     MPEGSplitterImpl *This = (MPEGSplitterImpl*)pPin->pin.pinInfo.pFilter;
459     HRESULT hr;
460     LONGLONG pos = 0; /* in bytes */
461     BYTE header[10];
462     int streamtype = 0;
463     LONGLONG total, avail;
464     AM_MEDIA_TYPE amt;
465     PIN_INFO piOutput;
466
467     IAsyncReader_Length(pPin->pReader, &total, &avail);
468     This->EndOfFile = total;
469
470     hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
471     if (SUCCEEDED(hr))
472         pos += 4;
473
474     /* Skip ID3 v2 tag, if any */
475     if (SUCCEEDED(hr) && !memcmp("ID3", header, 3))
476     do {
477         UINT length;
478         hr = IAsyncReader_SyncRead(pPin->pReader, pos, 6, header + 4);
479         if (FAILED(hr))
480             break;
481         pos += 6;
482         TRACE("Found ID3 v2.%d.%d\n", header[3], header[4]);
483         length  = (header[6] & 0x7F) << 21;
484         length += (header[7] & 0x7F) << 14;
485         length += (header[8] & 0x7F) << 7;
486         length += (header[9] & 0x7F);
487         TRACE("Length: %u\n", length);
488         pos += length;
489
490         /* Read the real header for the mpeg splitter */
491         hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
492         if (SUCCEEDED(hr))
493             pos += 4;
494         TRACE("%x:%x:%x:%x\n", header[0], header[1], header[2], header[3]);
495     } while (0);
496
497     while(SUCCEEDED(hr) && !(streamtype=MPEGSplitter_head_check(header)))
498     {
499         TRACE("%x:%x:%x:%x\n", header[0], header[1], header[2], header[3]);
500         /* No valid header yet; shift by a byte and check again */
501         memmove(header, header+1, 3);
502         hr = IAsyncReader_SyncRead(pPin->pReader, pos++, 1, header + 3);
503     }
504     if (FAILED(hr))
505         return hr;
506     pos -= 4;
507     This->begin_offset = pos;
508     memcpy(This->header, header, 4);
509
510     This->seektable[0].bytepos = pos;
511     This->seektable[0].timepos = 0;
512
513     switch(streamtype)
514     {
515         case MPEG_AUDIO_HEADER:
516         {
517             LONGLONG duration = 0;
518             DWORD last_entry = 0;
519
520             DWORD ticks = GetTickCount();
521
522             hr = MPEGSplitter_init_audio(This, header, &piOutput, &amt);
523             if (SUCCEEDED(hr))
524             {
525                 WAVEFORMATEX *format = (WAVEFORMATEX*)amt.pbFormat;
526
527                 props->cbAlign = 1;
528                 props->cbPrefix = 0;
529                 /* Make the output buffer a multiple of the frame size */
530                 props->cbBuffer = 0x4000 / format->nBlockAlign *
531                                  format->nBlockAlign;
532                 props->cBuffers = 3;
533                 hr = Parser_AddPin(&(This->Parser), &piOutput, props, &amt);
534             }
535
536             if (FAILED(hr))
537             {
538                 if (amt.pbFormat)
539                     CoTaskMemFree(amt.pbFormat);
540                 ERR("Could not create pin for MPEG audio stream (%x)\n", hr);
541                 break;
542             }
543
544             /* Check for idv1 tag, and remove it from stream if found */
545             hr = IAsyncReader_SyncRead(pPin->pReader, This->EndOfFile-128, 3, header+4);
546             if (FAILED(hr))
547                 break;
548             if (!strncmp((char*)header+4, "TAG", 3))
549                 This->EndOfFile -= 128;
550             This->Parser.pInputPin->rtStop = MEDIATIME_FROM_BYTES(This->EndOfFile);
551             This->Parser.pInputPin->rtStart = This->Parser.pInputPin->rtCurrent = MEDIATIME_FROM_BYTES(This->begin_offset);
552
553             /* http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm has a whole read up on audio headers */
554             while (pos + 3 < This->EndOfFile)
555             {
556                 LONGLONG length = 0;
557                 hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
558                 if (hr != S_OK)
559                     break;
560                 while (parse_header(header, &length, &duration))
561                 {
562                     /* No valid header yet; shift by a byte and check again */
563                     memmove(header, header+1, 3);
564                     hr = IAsyncReader_SyncRead(pPin->pReader, pos++, 1, header + 3);
565                     if (hr != S_OK || This->EndOfFile - pos < 4)
566                        break;
567                 }
568                 pos += length;
569
570                 if (This->seektable && (duration / SEEK_INTERVAL) > last_entry)
571                 {
572                     if (last_entry + 1 > duration / SEEK_INTERVAL)
573                     {
574                         ERR("Somehow skipped %d interval lengths instead of 1\n", (DWORD)(duration/SEEK_INTERVAL) - (last_entry + 1));
575                     }
576                     ++last_entry;
577
578                     TRACE("Entry: %u\n", last_entry);
579                     if (last_entry >= This->seek_entries)
580                     {
581                         This->seek_entries += 64;
582                         This->seektable = CoTaskMemRealloc(This->seektable, (This->seek_entries)*sizeof(struct seek_entry));
583                     }
584                     This->seektable[last_entry].bytepos = pos;
585                     This->seektable[last_entry].timepos = duration;
586                 }
587
588                 TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(pos >> 32), (DWORD)pos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
589             }
590             hr = S_OK;
591             TRACE("Duration: %d seconds\n", (DWORD)(duration / 10000000));
592             TRACE("Parsing took %u ms\n", GetTickCount() - ticks);
593             This->duration = duration;
594
595             This->Parser.sourceSeeking.llCurrent = 0;
596             This->Parser.sourceSeeking.llDuration = duration;
597             This->Parser.sourceSeeking.llStop = duration;
598             break;
599         }
600         case MPEG_VIDEO_HEADER:
601             FIXME("MPEG video processing not yet supported!\n");
602             hr = E_FAIL;
603             break;
604         case MPEG_SYSTEM_HEADER:
605             FIXME("MPEG system streams not yet supported!\n");
606             hr = E_FAIL;
607             break;
608
609         default:
610             break;
611     }
612     This->position = 0;
613
614     return hr;
615 }
616
617 static HRESULT MPEGSplitter_cleanup(LPVOID iface)
618 {
619     MPEGSplitterImpl *This = iface;
620
621     TRACE("(%p)\n", This);
622
623     return S_OK;
624 }
625
626 static HRESULT WINAPI MPEGSplitter_seek(IMediaSeeking *iface)
627 {
628     MPEGSplitterImpl *This = impl_from_IMediaSeeking(iface);
629     PullPin *pPin = This->Parser.pInputPin;
630     LONGLONG newpos, timepos, bytepos;
631     HRESULT hr = S_OK;
632     BYTE header[4];
633
634     newpos = This->Parser.sourceSeeking.llCurrent;
635
636     if (newpos > This->duration)
637     {
638         WARN("Requesting position %x%08x beyond end of stream %x%08x\n", (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(This->duration>>32), (DWORD)This->duration);
639         return E_INVALIDARG;
640     }
641
642     if (This->position/1000000 == newpos/1000000)
643     {
644         TRACE("Requesting position %x%08x same as current position %x%08x\n", (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(This->position>>32), (DWORD)This->position);
645         return S_OK;
646     }
647
648     /* Position, cached */
649     bytepos = This->seektable[newpos / SEEK_INTERVAL].bytepos;
650     timepos = This->seektable[newpos / SEEK_INTERVAL].timepos;
651
652     hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
653     while (bytepos + 3 < This->EndOfFile)
654     {
655         LONGLONG length = 0;
656         hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
657         if (hr != S_OK || timepos >= newpos)
658             break;
659
660         while (parse_header(header, &length, &timepos) && bytepos + 3 < This->EndOfFile)
661         {
662             /* No valid header yet; shift by a byte and check again */
663             memmove(header, header+1, 3);
664             hr = IAsyncReader_SyncRead(pPin->pReader, ++bytepos, 1, header + 3);
665             if (hr != S_OK)
666                 break;
667          }
668          bytepos += length;
669          TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(bytepos >> 32), (DWORD)bytepos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
670     }
671
672     if (SUCCEEDED(hr))
673     {
674         PullPin *pin = This->Parser.pInputPin;
675         IPin *victim = NULL;
676
677         TRACE("Moving sound to %08u bytes!\n", (DWORD)bytepos);
678
679         EnterCriticalSection(&pin->thread_lock);
680         IPin_BeginFlush((IPin *)pin);
681
682         /* Make sure this is done while stopped, BeginFlush takes care of this */
683         EnterCriticalSection(&This->Parser.filter.csFilter);
684         memcpy(This->header, header, 4);
685         IPin_ConnectedTo(This->Parser.ppPins[1], &victim);
686         if (victim)
687         {
688             IPin_NewSegment(victim, newpos, This->duration, pin->dRate);
689             IPin_Release(victim);
690         }
691
692         pin->rtStart = pin->rtCurrent = MEDIATIME_FROM_BYTES(bytepos);
693         pin->rtStop = MEDIATIME_FROM_BYTES((REFERENCE_TIME)This->EndOfFile);
694         This->seek = TRUE;
695         This->position = newpos;
696         LeaveCriticalSection(&This->Parser.filter.csFilter);
697
698         TRACE("Done flushing\n");
699         IPin_EndFlush((IPin *)pin);
700         LeaveCriticalSection(&pin->thread_lock);
701     }
702     return hr;
703 }
704
705 static HRESULT MPEGSplitter_disconnect(LPVOID iface)
706 {
707     /* TODO: Find memory leaks etc */
708     return S_OK;
709 }
710
711 static HRESULT MPEGSplitter_first_request(LPVOID iface)
712 {
713     MPEGSplitterImpl *This = iface;
714     PullPin *pin = This->Parser.pInputPin;
715     HRESULT hr;
716     LONGLONG length;
717     IMediaSample *sample;
718
719     TRACE("Seeking? %d\n", This->seek);
720     assert(parse_header(This->header, &length, NULL) == S_OK);
721
722     if (pin->rtCurrent >= pin->rtStop)
723     {
724         /* Last sample has already been queued, request nothing more */
725         FIXME("Done!\n");
726         return S_OK;
727     }
728
729     hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
730
731     pin->rtNext = pin->rtCurrent;
732     if (SUCCEEDED(hr))
733     {
734         LONGLONG rtSampleStart = pin->rtNext;
735         /* Add 4 for the next header, which should hopefully work */
736         LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(length + 4);
737
738         if (rtSampleStop > pin->rtStop)
739             rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
740
741         hr = IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
742
743         pin->rtCurrent = pin->rtNext;
744         pin->rtNext = rtSampleStop;
745
746         IMediaSample_SetPreroll(sample, FALSE);
747         IMediaSample_SetDiscontinuity(sample, This->seek);
748         IMediaSample_SetSyncPoint(sample, 1);
749         This->seek = 0;
750
751         hr = IAsyncReader_Request(pin->pReader, sample, 0);
752     }
753     if (FAILED(hr))
754         ERR("Horsemen of the apocalypse came to bring error 0x%08x\n", hr);
755
756     return hr;
757 }
758
759 static const IBaseFilterVtbl MPEGSplitter_Vtbl =
760 {
761     Parser_QueryInterface,
762     Parser_AddRef,
763     Parser_Release,
764     Parser_GetClassID,
765     Parser_Stop,
766     Parser_Pause,
767     Parser_Run,
768     Parser_GetState,
769     Parser_SetSyncSource,
770     Parser_GetSyncSource,
771     Parser_EnumPins,
772     Parser_FindPin,
773     Parser_QueryFilterInfo,
774     Parser_JoinFilterGraph,
775     Parser_QueryVendorInfo
776 };
777
778 HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
779 {
780     MPEGSplitterImpl *This;
781     HRESULT hr = E_FAIL;
782
783     TRACE("(%p, %p)\n", pUnkOuter, ppv);
784
785     *ppv = NULL;
786
787     if (pUnkOuter)
788         return CLASS_E_NOAGGREGATION;
789
790     This = CoTaskMemAlloc(sizeof(MPEGSplitterImpl));
791     if (!This)
792         return E_OUTOFMEMORY;
793
794     ZeroMemory(This, sizeof(MPEGSplitterImpl));
795     This->seektable = CoTaskMemAlloc(sizeof(struct seek_entry) * 64);
796     if (!This->seektable)
797     {
798         CoTaskMemFree(This);
799         return E_OUTOFMEMORY;
800     }
801     This->seek_entries = 64;
802
803     hr = Parser_Create(&(This->Parser), &MPEGSplitter_Vtbl, &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, MPEGSplitter_disconnect, MPEGSplitter_first_request, NULL, NULL, MPEGSplitter_seek, NULL);
804     if (FAILED(hr))
805     {
806         CoTaskMemFree(This);
807         return hr;
808     }
809     This->seek = 1;
810
811     /* Note: This memory is managed by the parser filter once created */
812     *ppv = This;
813
814     return hr;
815 }