ReactOS  0.4.14-dev-98-gb0d4763
mpegsplit.c
Go to the documentation of this file.
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 "pin.h"
29 
30 #include "uuids.h"
31 #include "mmreg.h"
32 #include "mmsystem.h"
33 
34 #include "wine/winternl.h"
35 
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38 
39 #include "parser.h"
40 
42 
43 #define SEQUENCE_HEADER_CODE 0xB3
44 #define PACK_START_CODE 0xBA
45 
46 #define SYSTEM_START_CODE 0xBB
47 #define AUDIO_ELEMENTARY_STREAM 0xC0
48 #define VIDEO_ELEMENTARY_STREAM 0xE0
49 
50 #define MPEG_SYSTEM_HEADER 3
51 #define MPEG_VIDEO_HEADER 2
52 #define MPEG_AUDIO_HEADER 1
53 #define MPEG_NO_HEADER 0
54 
55 typedef struct MPEGSplitterImpl
56 {
63 
64  /* Whether we just seeked (or started playing) */
67 
69 {
70  return CONTAINING_RECORD(iface, MPEGSplitterImpl, Parser.filter.IBaseFilter_iface);
71 }
72 
74 {
75  return CONTAINING_RECORD(iface, MPEGSplitterImpl, Parser.sourceSeeking.IMediaSeeking_iface);
76 }
77 
79 {
80  return CONTAINING_RECORD(iface, MPEGSplitterImpl, IAMStreamSelect_iface);
81 }
82 
84 {
85  /* If this is a possible start code, check for a system or video header */
86  if (header[0] == 0 && header[1] == 0 && header[2] == 1)
87  {
88  /* Check if we got a system or elementary stream start code */
89  if (header[3] == PACK_START_CODE ||
92  return MPEG_SYSTEM_HEADER;
93 
94  /* Check for a MPEG video sequence start code */
95  if (header[3] == SEQUENCE_HEADER_CODE)
96  return MPEG_VIDEO_HEADER;
97  }
98 
99  /* This should give a good guess if we have an MPEG audio header */
100  if(header[0] == 0xff && ((header[1]>>5)&0x7) == 0x7 &&
101  ((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf &&
102  ((header[2]>>2)&0x3) != 0x3)
103  return MPEG_AUDIO_HEADER;
104 
105  /* Nothing yet.. */
106  return MPEG_NO_HEADER;
107 }
108 
109 static const WCHAR wszAudioStream[] = {'A','u','d','i','o',0};
110 
111 static const DWORD freqs[10] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000, 0 };
112 
113 static const DWORD tabsel_123[2][3][16] = {
114  { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
115  {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
116  {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
117 
118  { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
119  {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
120  {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
121 };
122 
123 static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration)
124 {
125  int bitrate_index, freq_index, lsf = 1, mpeg1, layer, padding, bitrate, length;
126  LONGLONG duration;
127 
129  {
130  FIXME("Not a valid header: %02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3]);
131  return E_INVALIDARG;
132  }
133 
134  mpeg1 = (header[1]>>4)&0x1;
135  if (mpeg1)
136  lsf = ((header[1]>>3)&0x1)^1;
137 
138  layer = 4-((header[1]>>1)&0x3);
139  bitrate_index = ((header[2]>>4)&0xf);
140  freq_index = ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6);
141  padding = ((header[2]>>1)&0x1);
142 
143  bitrate = tabsel_123[lsf][layer-1][bitrate_index] * 1000;
144  if (!bitrate)
145  {
146  FIXME("Not a valid header: %02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3]);
147  return E_INVALIDARG;
148  }
149 
150  if (layer == 1)
151  length = 4 * (12 * bitrate / freqs[freq_index] + padding);
152  else if (layer == 2)
153  length = 144 * bitrate / freqs[freq_index] + padding;
154  else if (layer == 3)
155  length = 144 * bitrate / (freqs[freq_index]<<lsf) + padding;
156  else
157  {
158  ERR("Impossible layer %d\n", layer);
159  return E_INVALIDARG;
160  }
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 
170 {
171  Parser_OutputPin * pOutputPin = unsafe_impl_Parser_OutputPin_from_IPin(This->Parser.ppPins[1]);
172  LONGLONG length = 0;
173  LONGLONG pos = BYTES_FROM_MEDIATIME(This->Parser.pInputPin->rtNext);
174  LONGLONG time = This->position, rtstop, rtstart;
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  hr = parse_header(fbuf, &length, &This->position);
184  assert(hr == S_OK);
185  IMediaSample_SetActualDataLength(pCurrentSample, length);
186 
187  /* Queue the next sample */
188  if (length + 4 == len)
189  {
190  PullPin *pin = This->Parser.pInputPin;
191  LONGLONG stop = BYTES_FROM_MEDIATIME(pin->rtStop);
192 
193  hr = S_OK;
194  memcpy(This->header, fbuf + length, 4);
195  while (FAILED(hr = parse_header(This->header, &length, NULL)))
196  {
197  memmove(This->header, This->header+1, 3);
198  if (pos + 4 >= stop)
199  break;
200  IAsyncReader_SyncRead(pin->pReader, ++pos, 1, This->header + 3);
201  }
202  pin->rtNext = MEDIATIME_FROM_BYTES(pos);
203 
204  if (SUCCEEDED(hr))
205  {
206  /* Remove 4 for the last header, which should hopefully work */
207  IMediaSample *sample = NULL;
208  LONGLONG rtSampleStart = pin->rtNext - MEDIATIME_FROM_BYTES(4);
209  LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(length + 4);
210 
211  if (rtSampleStop > pin->rtStop)
212  rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
213 
214  hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
215  if (SUCCEEDED(hr))
216  {
217  IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
218  IMediaSample_SetPreroll(sample, FALSE);
219  IMediaSample_SetDiscontinuity(sample, FALSE);
220  IMediaSample_SetSyncPoint(sample, TRUE);
221  hr = IAsyncReader_Request(pin->pReader, sample, 0);
222  if (SUCCEEDED(hr))
223  {
224  pin->rtCurrent = rtSampleStart;
225  pin->rtNext = rtSampleStop;
226  }
227  else
228  IMediaSample_Release(sample);
229  }
230  if (FAILED(hr))
231  FIXME("o_Ox%08x\n", hr);
232  }
233  }
234  /* If not, we're presumably at the end of file */
235 
236  TRACE("Media time : %u.%03u\n", (DWORD)(This->position/10000000), (DWORD)((This->position/10000)%1000));
237 
238  if (IMediaSample_IsDiscontinuity(pCurrentSample) == S_OK) {
239  IPin *victim;
240  EnterCriticalSection(&This->Parser.filter.csFilter);
241  pOutputPin->pin.pin.tStart = time;
242  pOutputPin->pin.pin.dRate = This->Parser.sourceSeeking.dRate;
243  hr = IPin_ConnectedTo(&pOutputPin->pin.pin.IPin_iface, &victim);
244  if (hr == S_OK)
245  {
246  hr = IPin_NewSegment(victim, time, This->Parser.sourceSeeking.llStop,
247  This->Parser.sourceSeeking.dRate);
248  if (hr != S_OK)
249  FIXME("NewSegment returns %08x\n", hr);
250  IPin_Release(victim);
251  }
252  LeaveCriticalSection(&This->Parser.filter.csFilter);
253  if (hr != S_OK)
254  return hr;
255  }
256  rtstart = (double)(time - pOutputPin->pin.pin.tStart) / pOutputPin->pin.pin.dRate;
257  rtstop = (double)(This->position - pOutputPin->pin.pin.tStart) / pOutputPin->pin.pin.dRate;
258  IMediaSample_SetTime(pCurrentSample, &rtstart, &rtstop);
259  IMediaSample_SetMediaTime(pCurrentSample, &time, &This->position);
260 
261  hr = BaseOutputPinImpl_Deliver(&pOutputPin->pin, pCurrentSample);
262 
263  if (hr != S_OK)
264  {
265  if (hr != S_FALSE)
266  TRACE("Error sending sample (%x)\n", hr);
267  else
268  TRACE("S_FALSE (%d), holding\n", IMediaSample_GetActualDataLength(pCurrentSample));
269  }
270 
271  return hr;
272 }
273 
274 
276 {
277  MPEGSplitterImpl *This = iface;
278  BYTE *pbSrcStream;
279  DWORD cbSrcStream = 0;
280  REFERENCE_TIME tStart, tStop, tAviStart = This->position;
281  HRESULT hr;
282 
283  hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
284  if (SUCCEEDED(hr))
285  {
286  cbSrcStream = IMediaSample_GetActualDataLength(pSample);
287  hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
288  }
289 
290  /* Flush occurring */
291  if (cbSrcStream == 0)
292  {
293  FIXME(".. Why do I need you?\n");
294  return S_OK;
295  }
296 
297  /* trace removed for performance reasons */
298  /* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */
299 
300  /* Now, try to find a new header */
301  hr = FillBuffer(This, pSample);
302  if (hr != S_OK)
303  {
304  WARN("Failed with hres: %08x!\n", hr);
305 
306  /* Unset progression if denied! */
307  if (hr == VFW_E_WRONG_STATE || hr == S_FALSE)
308  {
309  memcpy(This->header, pbSrcStream, 4);
310  This->Parser.pInputPin->rtCurrent = tStart;
311  This->position = tAviStart;
312  }
313  }
314 
315  if (BYTES_FROM_MEDIATIME(tStop) >= This->EndOfFile || This->position >= This->Parser.sourceSeeking.llStop)
316  {
317  unsigned int i;
318 
319  TRACE("End of file reached\n");
320 
321  for (i = 0; i < This->Parser.cStreams; i++)
322  {
323  IPin* ppin;
324 
325  hr = IPin_ConnectedTo(This->Parser.ppPins[i+1], &ppin);
326  if (SUCCEEDED(hr))
327  {
328  hr = IPin_EndOfStream(ppin);
329  IPin_Release(ppin);
330  }
331  if (FAILED(hr))
332  WARN("Error sending EndOfStream to pin %u (%x)\n", i, hr);
333  }
334 
335  /* Force the pullpin thread to stop */
336  hr = S_FALSE;
337  }
338 
339  return hr;
340 }
341 
342 
344 {
345  if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
346  return S_FALSE;
347 
348  if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Audio))
349  return S_OK;
350 
351  if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Video))
352  FIXME("MPEG-1 video streams not yet supported.\n");
353  else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1System))
354  FIXME("MPEG-1 system streams not yet supported.\n");
355  else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1VideoCD))
356  FIXME("MPEG-1 VideoCD streams not yet supported.\n");
357  else FIXME("%s\n", debugstr_guid(&pmt->subtype));
358 
359  return S_FALSE;
360 }
361 
362 
364 {
366  int bitrate_index;
367  int freq_index;
368  int mode_ext;
369  int emphasis;
370  int padding;
371  int lsf = 1;
372  int mpeg1;
373  int layer;
374  int mode;
375 
376  ZeroMemory(pamt, sizeof(*pamt));
377  ppiOutput->dir = PINDIR_OUTPUT;
378  ppiOutput->pFilter = &This->Parser.filter.IBaseFilter_iface;
379  wsprintfW(ppiOutput->achName, wszAudioStream);
380 
381  pamt->formattype = FORMAT_WaveFormatEx;
382  pamt->majortype = MEDIATYPE_Audio;
383  pamt->subtype = MEDIASUBTYPE_MPEG1AudioPayload;
384 
385  pamt->lSampleSize = 0;
386  pamt->bFixedSizeSamples = FALSE;
387  pamt->bTemporalCompression = 0;
388 
389  mpeg1 = (header[1]>>4)&0x1;
390  if (mpeg1)
391  lsf = ((header[1]>>3)&0x1)^1;
392 
393  layer = 4-((header[1]>>1)&0x3);
394  bitrate_index = ((header[2]>>4)&0xf);
395  padding = ((header[2]>>1)&0x1);
396  freq_index = ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6);
397  mode = ((header[3]>>6)&0x3);
398  mode_ext = ((header[3]>>4)&0x3);
399  emphasis = ((header[3]>>0)&0x3);
400 
401  if (!bitrate_index)
402  {
403  /* Set to highest bitrate so samples will fit in for sure */
404  FIXME("Variable-bitrate audio not fully supported.\n");
405  bitrate_index = 15;
406  }
407 
408  pamt->cbFormat = ((layer==3)? sizeof(MPEGLAYER3WAVEFORMAT) :
409  sizeof(MPEG1WAVEFORMAT));
410  pamt->pbFormat = CoTaskMemAlloc(pamt->cbFormat);
411  if (!pamt->pbFormat)
412  return E_OUTOFMEMORY;
413  ZeroMemory(pamt->pbFormat, pamt->cbFormat);
414  format = (WAVEFORMATEX*)pamt->pbFormat;
415 
416  format->wFormatTag = ((layer == 3) ? WAVE_FORMAT_MPEGLAYER3 :
418  format->nChannels = ((mode == 3) ? 1 : 2);
419  format->nSamplesPerSec = freqs[freq_index];
420  format->nAvgBytesPerSec = tabsel_123[lsf][layer-1][bitrate_index] * 1000 / 8;
421 
422  if (layer == 3)
423  format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 /
424  (format->nSamplesPerSec<<lsf) + padding;
425  else if (layer == 2)
426  format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 /
427  format->nSamplesPerSec + padding;
428  else
429  format->nBlockAlign = 4 * (format->nAvgBytesPerSec * 8 * 12 / format->nSamplesPerSec + padding);
430 
431  format->wBitsPerSample = 0;
432 
433  if (layer == 3)
434  {
436 
438 
439  mp3format->wID = MPEGLAYER3_ID_MPEG;
441  mp3format->nBlockSize = format->nBlockAlign;
442  mp3format->nFramesPerBlock = 1;
443 
444  /* Beware the evil magic numbers. This struct is apparently horribly
445  * under-documented, and the only references I could find had it being
446  * set to this with no real explanation. It works fine though, so I'm
447  * not complaining (yet).
448  */
449  mp3format->nCodecDelay = 1393;
450  }
451  else
452  {
453  MPEG1WAVEFORMAT *mpgformat = (MPEG1WAVEFORMAT*)format;
454 
455  format->cbSize = 22;
456 
457  mpgformat->fwHeadLayer = ((layer == 1) ? ACM_MPEG_LAYER1 :
458  ((layer == 2) ? ACM_MPEG_LAYER2 :
459  ACM_MPEG_LAYER3));
460  mpgformat->dwHeadBitrate = format->nAvgBytesPerSec * 8;
461  mpgformat->fwHeadMode = ((mode == 3) ? ACM_MPEG_SINGLECHANNEL :
462  ((mode == 2) ? ACM_MPEG_DUALCHANNEL :
463  ((mode == 1) ? ACM_MPEG_JOINTSTEREO :
464  ACM_MPEG_STEREO)));
465  mpgformat->fwHeadModeExt = ((mode == 1) ? 0x0F : (1<<mode_ext));
466  mpgformat->wHeadEmphasis = emphasis + 1;
467  mpgformat->fwHeadFlags = ACM_MPEG_ID_MPEG1;
468  }
469  pamt->subtype.Data1 = format->wFormatTag;
470 
471  TRACE("MPEG audio stream detected:\n"
472  "\tLayer %d (%#x)\n"
473  "\tFrequency: %d\n"
474  "\tChannels: %d (%d)\n"
475  "\tBytesPerSec: %d\n",
476  layer, format->wFormatTag, format->nSamplesPerSec,
477  format->nChannels, mode, format->nAvgBytesPerSec);
478 
479  dump_AM_MEDIA_TYPE(pamt);
480 
481  return S_OK;
482 }
483 
484 
486 {
487  PullPin *pPin = impl_PullPin_from_IPin(iface);
488  MPEGSplitterImpl *This = (MPEGSplitterImpl*)pPin->pin.pinInfo.pFilter;
489  HRESULT hr;
490  LONGLONG pos = 0; /* in bytes */
491  BYTE header[10];
492  int streamtype;
493  LONGLONG total, avail;
494  AM_MEDIA_TYPE amt;
495  PIN_INFO piOutput;
496 
497  IAsyncReader_Length(pPin->pReader, &total, &avail);
498  This->EndOfFile = total;
499 
500  hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
501  if (SUCCEEDED(hr))
502  pos += 4;
503 
504  /* Skip ID3 v2 tag, if any */
505  if (SUCCEEDED(hr) && !memcmp("ID3", header, 3))
506  do {
507  UINT length = 0;
508  hr = IAsyncReader_SyncRead(pPin->pReader, pos, 6, header + 4);
509  if (FAILED(hr))
510  break;
511  pos += 6;
512  TRACE("Found ID3 v2.%d.%d\n", header[3], header[4]);
513  if(header[3] <= 4 && header[4] != 0xff &&
514  (header[5]&0x0f) == 0 && (header[6]&0x80) == 0 &&
515  (header[7]&0x80) == 0 && (header[8]&0x80) == 0 &&
516  (header[9]&0x80) == 0)
517  {
518  length = (header[6]<<21) | (header[7]<<14) |
519  (header[8]<< 7) | (header[9] );
520  if((header[5]&0x10))
521  length += 10;
522  TRACE("Length: %u\n", length);
523  }
524  pos += length;
525 
526  /* Read the real header for the mpeg splitter */
527  hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
528  if (SUCCEEDED(hr))
529  pos += 4;
530  } while (0);
531 
532  while(SUCCEEDED(hr))
533  {
534  TRACE("Testing header %x:%x:%x:%x\n", header[0], header[1], header[2], header[3]);
535 
536  streamtype = MPEGSplitter_head_check(header);
537  if (streamtype == MPEG_AUDIO_HEADER)
538  {
540  if (parse_header(header, &length, NULL) == S_OK)
541  {
542  BYTE next_header[4];
543  /* Ensure we have a valid header by seeking for the next frame, some bad
544  * encoded ID3v2 may have an incorrect length and we end up finding bytes
545  * like FF FE 00 28 which are nothing more than a Unicode BOM followed by
546  * ')' character from inside a ID3v2 tag. Unfortunately that sequence
547  * matches like a valid mpeg audio header.
548  */
549  hr = IAsyncReader_SyncRead(pPin->pReader, pos + length - 4, 4, next_header);
550  if (FAILED(hr))
551  break;
552  if (parse_header(next_header, &length, NULL) == S_OK)
553  break;
554  TRACE("%x:%x:%x:%x is a fake audio header, looking for next...\n",
555  header[0], header[1], header[2], header[3]);
556  }
557  }
558  else if (streamtype) /* Video or System stream */
559  break;
560 
561  /* No valid header yet; shift by a byte and check again */
562  memmove(header, header+1, 3);
563  hr = IAsyncReader_SyncRead(pPin->pReader, pos++, 1, header + 3);
564  }
565  if (FAILED(hr))
566  return hr;
567  pos -= 4;
568  This->begin_offset = pos;
569  memcpy(This->header, header, 4);
570 
571  switch(streamtype)
572  {
573  case MPEG_AUDIO_HEADER:
574  {
575  LONGLONG duration = 0;
577 
578  hr = MPEGSplitter_init_audio(This, header, &piOutput, &amt);
579  if (SUCCEEDED(hr))
580  {
581  format = (WAVEFORMATEX*)amt.pbFormat;
582 
583  props->cbAlign = 1;
584  props->cbPrefix = 0;
585  /* Make the output buffer a multiple of the frame size */
586  props->cbBuffer = 0x4000 / format->nBlockAlign *
587  format->nBlockAlign;
588  props->cBuffers = 3;
589  hr = Parser_AddPin(&(This->Parser), &piOutput, props, &amt);
590  }
591 
592  if (FAILED(hr))
593  {
594  CoTaskMemFree(amt.pbFormat);
595  ERR("Could not create pin for MPEG audio stream (%x)\n", hr);
596  break;
597  }
598 
599  /* Check for idv1 tag, and remove it from stream if found */
600  hr = IAsyncReader_SyncRead(pPin->pReader, This->EndOfFile-128, 3, header);
601  if (FAILED(hr))
602  break;
603  if (!strncmp((char*)header, "TAG", 3))
604  This->EndOfFile -= 128;
605  This->Parser.pInputPin->rtStop = MEDIATIME_FROM_BYTES(This->EndOfFile);
606  This->Parser.pInputPin->rtStart = This->Parser.pInputPin->rtCurrent = MEDIATIME_FROM_BYTES(This->begin_offset);
607 
608  duration = (This->EndOfFile-This->begin_offset) * 10000000 / format->nAvgBytesPerSec;
609  TRACE("Duration: %d seconds\n", (DWORD)(duration / 10000000));
610 
611  This->Parser.sourceSeeking.llCurrent = 0;
612  This->Parser.sourceSeeking.llDuration = duration;
613  This->Parser.sourceSeeking.llStop = duration;
614  break;
615  }
616  case MPEG_VIDEO_HEADER:
617  FIXME("MPEG video processing not yet supported!\n");
618  hr = E_FAIL;
619  break;
620  case MPEG_SYSTEM_HEADER:
621  FIXME("MPEG system streams not yet supported!\n");
622  hr = E_FAIL;
623  break;
624 
625  default:
626  break;
627  }
628  This->position = 0;
629 
630  return hr;
631 }
632 
634 {
635  MPEGSplitterImpl *This = iface;
636 
637  TRACE("(%p)\n", This);
638 
639  return S_OK;
640 }
641 
643 {
645  PullPin *pPin = This->Parser.pInputPin;
646  LONGLONG newpos, timepos, bytepos;
648  BYTE header[4];
649 
650  newpos = This->Parser.sourceSeeking.llCurrent;
651  if (This->position/1000000 == newpos/1000000)
652  {
653  TRACE("Requesting position %x%08x same as current position %x%08x\n", (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(This->position>>32), (DWORD)This->position);
654  return S_OK;
655  }
656 
657  bytepos = This->begin_offset;
658  timepos = 0;
659  /* http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm has a whole read up on audio headers */
660  while (bytepos + 3 < This->EndOfFile)
661  {
662  LONGLONG duration = timepos;
663  LONGLONG length = 0;
664  hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
665  if (hr != S_OK)
666  break;
667  while ((hr=parse_header(header, &length, &duration)) != S_OK &&
668  bytepos + 4 < This->EndOfFile)
669  {
670  /* No valid header yet; shift by a byte and check again */
671  memmove(header, header+1, 3);
672  hr = IAsyncReader_SyncRead(pPin->pReader, ++bytepos + 3, 1, header + 3);
673  if (hr != S_OK)
674  break;
675  }
676  if (hr != S_OK || duration > newpos)
677  break;
678  bytepos += length;
679  timepos = duration;
680  }
681 
682  if (SUCCEEDED(hr))
683  {
684  PullPin *pin = This->Parser.pInputPin;
685 
686  TRACE("Moving sound to %08u bytes!\n", (DWORD)bytepos);
687 
688  EnterCriticalSection(&pin->thread_lock);
689  IPin_BeginFlush(&pin->pin.IPin_iface);
690 
691  /* Make sure this is done while stopped, BeginFlush takes care of this */
692  EnterCriticalSection(&This->Parser.filter.csFilter);
693  memcpy(This->header, header, 4);
694 
695  pin->rtStart = pin->rtCurrent = MEDIATIME_FROM_BYTES(bytepos);
696  pin->rtStop = MEDIATIME_FROM_BYTES((REFERENCE_TIME)This->EndOfFile);
697  This->seek = TRUE;
698  This->position = newpos;
699  LeaveCriticalSection(&This->Parser.filter.csFilter);
700 
701  TRACE("Done flushing\n");
702  IPin_EndFlush(&pin->pin.IPin_iface);
703  LeaveCriticalSection(&pin->thread_lock);
704  }
705  return hr;
706 }
707 
709 {
710  /* TODO: Find memory leaks etc */
711  return S_OK;
712 }
713 
715 {
716  MPEGSplitterImpl *This = iface;
717  PullPin *pin = This->Parser.pInputPin;
718  HRESULT hr;
720  IMediaSample *sample;
721 
722  TRACE("Seeking? %d\n", This->seek);
723 
724  hr = parse_header(This->header, &length, NULL);
725  assert(hr == S_OK);
726 
727  if (pin->rtCurrent >= pin->rtStop)
728  {
729  /* Last sample has already been queued, request nothing more */
730  FIXME("Done!\n");
731  return S_OK;
732  }
733 
734  hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
735 
736  pin->rtNext = pin->rtCurrent;
737  if (SUCCEEDED(hr))
738  {
739  LONGLONG rtSampleStart = pin->rtNext;
740  /* Add 4 for the next header, which should hopefully work */
741  LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(length + 4);
742 
743  if (rtSampleStop > pin->rtStop)
744  rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
745 
746  IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
747  IMediaSample_SetPreroll(sample, FALSE);
748  IMediaSample_SetDiscontinuity(sample, TRUE);
749  IMediaSample_SetSyncPoint(sample, 1);
750  This->seek = FALSE;
751 
752  hr = IAsyncReader_Request(pin->pReader, sample, 0);
753  if (SUCCEEDED(hr))
754  {
755  pin->rtCurrent = pin->rtNext;
756  pin->rtNext = rtSampleStop;
757  }
758  else
759  IMediaSample_Release(sample);
760  }
761  if (FAILED(hr))
762  ERR("Horsemen of the apocalypse came to bring error 0x%08x\n", hr);
763 
764  return hr;
765 }
766 
768 {
770  TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
771 
772  *ppv = NULL;
773 
776  || IsEqualIID(riid, &IID_IMediaFilter)
778  *ppv = iface;
779  else if ( IsEqualIID(riid, &IID_IAMStreamSelect) )
780  *ppv = &This->IAMStreamSelect_iface;
781 
782  if (*ppv)
783  {
784  IBaseFilter_AddRef(iface);
785  return S_OK;
786  }
787 
788  if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
789  FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
790 
791  return E_NOINTERFACE;
792 }
793 
794 static const IBaseFilterVtbl MPEGSplitter_Vtbl =
795 {
800  Parser_Stop,
801  Parser_Pause,
802  Parser_Run,
811 };
812 
814 {
816 
817  return IBaseFilter_QueryInterface(&This->Parser.filter.IBaseFilter_iface, riid, ppv);
818 }
819 
821 {
823 
824  return IBaseFilter_AddRef(&This->Parser.filter.IBaseFilter_iface);
825 }
826 
828 {
830 
831  return IBaseFilter_Release(&This->Parser.filter.IBaseFilter_iface);
832 }
833 
835 {
837 
838  FIXME("(%p/%p)->(%p) stub!\n", This, iface, streams);
839 
840  return E_NOTIMPL;
841 }
842 
844 {
846 
847  FIXME("(%p/%p)->(%d,%p,%p,%p,%p,%p,%p,%p) stub!\n", This, iface, index, media_type, flags, lcid, group, name, object, unknown);
848 
849  return E_NOTIMPL;
850 }
851 
853 {
855 
856  FIXME("(%p/%p)->(%d,%x) stub!\n", This, iface, index, flags);
857 
858  return E_NOTIMPL;
859 }
860 
861 static const IAMStreamSelectVtbl AMStreamSelectVtbl =
862 {
869 };
870 
872 {
874  HRESULT hr = E_FAIL;
875 
876  TRACE("(%p, %p)\n", pUnkOuter, ppv);
877 
878  *ppv = NULL;
879 
880  if (pUnkOuter)
881  return CLASS_E_NOAGGREGATION;
882 
884  if (!This)
885  return E_OUTOFMEMORY;
886 
887  ZeroMemory(This, sizeof(MPEGSplitterImpl));
889  if (FAILED(hr))
890  {
892  return hr;
893  }
894  This->IAMStreamSelect_iface.lpVtbl = &AMStreamSelectVtbl;
895  This->seek = TRUE;
896 
897  /* Note: This memory is managed by the parser filter once created */
898  *ppv = &This->Parser.filter.IBaseFilter_iface;
899 
900  return hr;
901 }
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
const GUID IID_IBaseFilter
static MPEGSplitterImpl * impl_from_IBaseFilter(IBaseFilter *iface)
Definition: mpegsplit.c:68
static MPEGSplitterImpl * impl_from_IAMStreamSelect(IAMStreamSelect *iface)
Definition: mpegsplit.c:78
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
static HRESULT WINAPI AMStreamSelect_Enable(IAMStreamSelect *iface, LONG index, DWORD flags)
Definition: mpegsplit.c:852
IAsyncReader * pReader
Definition: pin.h:77
void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *pmt)
Definition: enummedia.c:27
#define REFIID
Definition: guiddef.h:118
#define TRUE
Definition: types.h:120
#define ACM_MPEG_SINGLECHANNEL
Definition: mmreg.h:423
#define E_NOINTERFACE
Definition: winerror.h:2364
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:422
HRESULT hr
Definition: shlfolder.c:183
BaseOutputPin pin
Definition: parser.h:46
REFIID riid
Definition: precomp.h:44
HRESULT WINAPI Parser_Pause(IBaseFilter *iface)
Definition: parser.c:279
const char * qzdebugstr_guid(const GUID *id)
Definition: main.c:279
#define MPEGLAYER3_WFX_EXTRA_BYTES
Definition: mmreg.h:439
IPin IPin_iface
Definition: strmbase.h:35
const GUID IID_IPersist
Definition: proxy.cpp:14
IAMStreamSelect IAMStreamSelect_iface
Definition: mpegsplit.c:58
#define ACM_MPEG_LAYER1
Definition: mmreg.h:416
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
#define WARN(fmt,...)
Definition: debug.h:111
#define MPEGLAYER3_FLAG_PADDING_ON
Definition: mmreg.h:446
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define assert(x)
Definition: debug.h:53
#define ZeroMemory
Definition: winbase.h:1642
LONGLONG EndOfFile
Definition: mpegsplit.c:59
#define ACM_MPEG_LAYER2
Definition: mmreg.h:417
HRESULT WINAPI Parser_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
Definition: parser.c:313
HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *pGraph, LPCWSTR pName)
Definition: parser.c:424
DWORD LCID
Definition: nls.h:13
__u16 time
Definition: mkdosfs.c:366
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define E_FAIL
Definition: ddrawi.h:102
static PullPin * impl_PullPin_from_IPin(IPin *iface)
Definition: pin.h:132
HRESULT WINAPI Parser_GetSyncSource(IBaseFilter *iface, IReferenceClock **ppClock)
Definition: parser.c:397
static int avail
Definition: adh-main.c:39
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
struct MPEGSplitterImpl MPEGSplitterImpl
#define WAVE_FORMAT_MPEG
Definition: mmreg.h:126
static const IBaseFilterVtbl MPEGSplitter_Vtbl
Definition: mpegsplit.c:794
static HRESULT MPEGSplitter_disconnect(LPVOID iface)
Definition: mpegsplit.c:708
Definition: regsvr.c:103
static HRESULT MPEGSplitter_init_audio(MPEGSplitterImpl *This, const BYTE *header, PIN_INFO *ppiOutput, AM_MEDIA_TYPE *pamt)
Definition: mpegsplit.c:363
static const DWORD tabsel_123[2][3][16]
Definition: mpegsplit.c:113
ParserImpl Parser
Definition: mpegsplit.c:57
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
Definition: pin.h:70
#define ACM_MPEG_JOINTSTEREO
Definition: mmreg.h:421
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
WINE_DEFAULT_DEBUG_CHANNEL(quartz)
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define FIXME(fmt,...)
Definition: debug.h:110
HRESULT WINAPI Parser_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
Definition: parser.c:409
#define MPEG_NO_HEADER
Definition: mpegsplit.c:53
#define S_FALSE
Definition: winerror.h:2357
BYTE header[4]
Definition: mpegsplit.c:62
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
#define E_INVALIDARG
Definition: ddrawi.h:101
static HRESULT WINAPI AMStreamSelect_QueryInterface(IAMStreamSelect *iface, REFIID riid, void **ppv)
Definition: mpegsplit.c:813
smooth NULL
Definition: ftsmooth.c:416
static const IAMStreamSelectVtbl AMStreamSelectVtbl
Definition: mpegsplit.c:861
struct mpeg1waveformat_tag MPEG1WAVEFORMAT
GLuint index
Definition: glext.h:6031
#define ACM_MPEG_ID_MPEG1
Definition: mmreg.h:428
#define debugstr_guid
Definition: kernel32.h:35
#define SEQUENCE_HEADER_CODE
Definition: mpegsplit.c:43
HRESULT WINAPI Parser_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
Definition: parser.c:404
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define ALIGNUP(value, boundary)
Definition: pin.c:33
#define MPEGLAYER3_ID_MPEG
Definition: mmreg.h:442
GLboolean GLuint group
Definition: glext.h:11120
GLenum GLuint GLint GLint layer
Definition: glext.h:7007
int64_t LONGLONG
Definition: typedefs.h:66
#define TRACE(s)
Definition: solgame.cpp:4
static const WCHAR wszAudioStream[]
Definition: mpegsplit.c:109
unsigned int padding
Definition: isohybrid.c:50
static HRESULT MPEGSplitter_cleanup(LPVOID iface)
Definition: mpegsplit.c:633
LONGLONG REFERENCE_TIME
Definition: dmusicks.h:9
HRESULT MPEGSplitter_create(IUnknown *pUnkOuter, LPVOID *ppv)
Definition: mpegsplit.c:871
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:77
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
#define MPEG_SYSTEM_HEADER
Definition: mpegsplit.c:50
uint64_t ULONGLONG
Definition: typedefs.h:65
const GUID IID_IUnknown
BasePin pin
Definition: strmbase.h:66
static HRESULT WINAPI AMStreamSelect_Info(IAMStreamSelect *iface, LONG index, AM_MEDIA_TYPE **media_type, DWORD *flags, LCID *lcid, DWORD *group, WCHAR **name, IUnknown **object, IUnknown **unknown)
Definition: mpegsplit.c:843
static MPEGSplitterImpl * impl_from_IMediaSeeking(IMediaSeeking *iface)
Definition: mpegsplit.c:73
#define WINAPI
Definition: msvc.h:8
static HRESULT WINAPI AMStreamSelect_Count(IAMStreamSelect *iface, DWORD *streams)
Definition: mpegsplit.c:834
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
REFERENCE_TIME tStart
Definition: strmbase.h:41
static ULONG WINAPI AMStreamSelect_Release(IAMStreamSelect *iface)
Definition: mpegsplit.c:827
ULONG WINAPI Parser_Release(IBaseFilter *iface)
Definition: parser.c:213
unsigned long DWORD
Definition: ntddk_ex.h:95
BasePin pin
Definition: pin.h:73
HRESULT WINAPI Parser_Stop(IBaseFilter *iface)
Definition: parser.c:241
WORD fwHeadModeExt
Definition: mmreg.h:409
Definition: id3.c:18
GLbitfield flags
Definition: glext.h:7161
#define BYTES_FROM_MEDIATIME(time)
HRESULT Parser_AddPin(ParserImpl *This, const PIN_INFO *piOutput, ALLOCATOR_PROPERTIES *props, const AM_MEDIA_TYPE *amt)
Definition: parser.c:446
static const DWORD freqs[10]
Definition: mpegsplit.c:111
double dRate
Definition: strmbase.h:43
WORD wHeadEmphasis
Definition: mmreg.h:410
#define WAVE_FORMAT_MPEGLAYER3
Definition: mmreg.h:127
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
static ULONG WINAPI AMStreamSelect_AddRef(IAMStreamSelect *iface)
Definition: mpegsplit.c:820
#define MPEG_VIDEO_HEADER
Definition: mpegsplit.c:51
HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo)
Definition: parser.c:429
DWORD begin_offset
Definition: mpegsplit.c:61
#define CLASS_E_NOAGGREGATION
Definition: winerror.h:2662
uint32_t DWORD_PTR
Definition: typedefs.h:63
GLenum mode
Definition: glext.h:6217
#define ACM_MPEG_LAYER3
Definition: mmreg.h:418
static HRESULT WINAPI MPEGSplitter_seek(IMediaSeeking *iface)
Definition: mpegsplit.c:642
#define ERR(fmt,...)
Definition: debug.h:109
#define ACM_MPEG_STEREO
Definition: mmreg.h:420
#define S_OK
Definition: intsafe.h:59
static HRESULT FillBuffer(MPEGSplitterImpl *This, IMediaSample *pCurrentSample)
Definition: mpegsplit.c:169
#define ACM_MPEG_DUALCHANNEL
Definition: mmreg.h:422
HRESULT WINAPI Parser_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
Definition: parser.c:361
static HRESULT MPEGSplitter_first_request(LPVOID iface)
Definition: mpegsplit.c:714
static Parser_OutputPin * unsafe_impl_Parser_OutputPin_from_IPin(IPin *iface)
Definition: parser.h:81
Definition: axcore.idl:91
#define E_NOTIMPL
Definition: ddrawi.h:99
#define VIDEO_ELEMENTARY_STREAM
Definition: mpegsplit.c:48
unsigned int UINT
Definition: ndis.h:50
#define MPEG_AUDIO_HEADER
Definition: mpegsplit.c:52
static HRESULT MPEGSplitter_query_accept(LPVOID iface, const AM_MEDIA_TYPE *pmt)
Definition: mpegsplit.c:343
HRESULT WINAPI Parser_SetSyncSource(IBaseFilter *iface, IReferenceClock *pClock)
Definition: parser.c:383
PIN_INFO pinInfo
Definition: strmbase.h:38
HRESULT WINAPI Parser_GetClassID(IBaseFilter *iface, CLSID *pClsid)
Definition: parser.c:228
HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin *This, IMediaSample *pSample)
Definition: pin.c:574
DWORD dwHeadBitrate
Definition: mmreg.h:407
Definition: name.c:36
static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration)
Definition: mpegsplit.c:123
static const WCHAR props[]
Definition: wbemdisp.c:288
LONGLONG position
Definition: mpegsplit.c:60
#define AUDIO_ELEMENTARY_STREAM
Definition: mpegsplit.c:47
unsigned int ULONG
Definition: retypes.h:1
HRESULT Parser_Create(ParserImpl *pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID *pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, STOPPROCESSPROC fnDone, SourceSeeking_ChangeStop stop, SourceSeeking_ChangeStart start, SourceSeeking_ChangeRate rate)
Definition: parser.c:96
static int MPEGSplitter_head_check(const BYTE *header)
Definition: mpegsplit.c:83
#define MEDIATIME_FROM_BYTES(x)
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define VFW_E_WRONG_STATE
Definition: vfwmsgs.h:78
ULONG WINAPI Parser_AddRef(IBaseFilter *iface)
Definition: parser.c:171
#define PACK_START_CODE
Definition: mpegsplit.c:44
HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo)
Definition: parser.c:419
const GUID IID_IPin
Definition: pincontrol.cpp:15
static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample *pSample, DWORD_PTR cookie)
Definition: mpegsplit.c:275
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:406
struct CFHEADER header
Definition: fdi.c:109
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
static HRESULT WINAPI MPEGSplitter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
Definition: mpegsplit.c:767
#define SUCCEEDED(hr)
Definition: intsafe.h:57
static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin, ALLOCATOR_PROPERTIES *props)
Definition: mpegsplit.c:485