ReactOS 0.4.15-dev-7889-g76290a6
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
55typedef 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 */
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
109static const WCHAR wszAudioStream[] = {'A','u','d','i','o',0};
110
111static const DWORD freqs[10] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000, 0 };
112
113static 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
123static 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 {
454
455 format->cbSize = 22;
456
457 mpgformat->fwHeadLayer = ((layer == 1) ? ACM_MPEG_LAYER1 :
458 ((layer == 2) ? ACM_MPEG_LAYER2 :
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 :
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);
489 HRESULT hr;
490 LONGLONG pos = 0; /* in bytes */
491 BYTE header[10];
492 int streamtype;
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 {
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 {
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 }
617 FIXME("MPEG video processing not yet supported!\n");
618 hr = E_FAIL;
619 break;
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
794static const IBaseFilterVtbl MPEGSplitter_Vtbl =
795{
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
861static 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)
882
884 if (!This)
885 return E_OUTOFMEMORY;
886
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 memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
static int avail
Definition: adh-main.c:39
@ PINDIR_OUTPUT
Definition: axcore.idl:42
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
const GUID IID_IUnknown
#define FIXME(fmt,...)
Definition: debug.h:111
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
const GUID IID_IBaseFilter
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
const char * qzdebugstr_guid(const GUID *id)
Definition: main.c:279
static const WCHAR wszAudioStream[]
Definition: mpegsplit.c:109
static const DWORD tabsel_123[2][3][16]
Definition: mpegsplit.c:113
static MPEGSplitterImpl * impl_from_IAMStreamSelect(IAMStreamSelect *iface)
Definition: mpegsplit.c:78
static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample *pSample, DWORD_PTR cookie)
Definition: mpegsplit.c:275
static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration)
Definition: mpegsplit.c:123
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 const IBaseFilterVtbl MPEGSplitter_Vtbl
Definition: mpegsplit.c:794
static HRESULT MPEGSplitter_init_audio(MPEGSplitterImpl *This, const BYTE *header, PIN_INFO *ppiOutput, AM_MEDIA_TYPE *pamt)
Definition: mpegsplit.c:363
#define MPEG_VIDEO_HEADER
Definition: mpegsplit.c:51
static HRESULT MPEGSplitter_query_accept(LPVOID iface, const AM_MEDIA_TYPE *pmt)
Definition: mpegsplit.c:343
#define MPEG_NO_HEADER
Definition: mpegsplit.c:53
static const DWORD freqs[10]
Definition: mpegsplit.c:111
static HRESULT WINAPI AMStreamSelect_Count(IAMStreamSelect *iface, DWORD *streams)
Definition: mpegsplit.c:834
static ULONG WINAPI AMStreamSelect_AddRef(IAMStreamSelect *iface)
Definition: mpegsplit.c:820
static MPEGSplitterImpl * impl_from_IBaseFilter(IBaseFilter *iface)
Definition: mpegsplit.c:68
HRESULT MPEGSplitter_create(IUnknown *pUnkOuter, LPVOID *ppv)
Definition: mpegsplit.c:871
static ULONG WINAPI AMStreamSelect_Release(IAMStreamSelect *iface)
Definition: mpegsplit.c:827
static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin, ALLOCATOR_PROPERTIES *props)
Definition: mpegsplit.c:485
#define AUDIO_ELEMENTARY_STREAM
Definition: mpegsplit.c:47
static HRESULT WINAPI AMStreamSelect_QueryInterface(IAMStreamSelect *iface, REFIID riid, void **ppv)
Definition: mpegsplit.c:813
static HRESULT WINAPI MPEGSplitter_seek(IMediaSeeking *iface)
Definition: mpegsplit.c:642
#define SEQUENCE_HEADER_CODE
Definition: mpegsplit.c:43
static HRESULT MPEGSplitter_cleanup(LPVOID iface)
Definition: mpegsplit.c:633
static MPEGSplitterImpl * impl_from_IMediaSeeking(IMediaSeeking *iface)
Definition: mpegsplit.c:73
#define MPEG_SYSTEM_HEADER
Definition: mpegsplit.c:50
static const IAMStreamSelectVtbl AMStreamSelectVtbl
Definition: mpegsplit.c:861
static HRESULT MPEGSplitter_first_request(LPVOID iface)
Definition: mpegsplit.c:714
static HRESULT WINAPI MPEGSplitter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
Definition: mpegsplit.c:767
static HRESULT WINAPI AMStreamSelect_Enable(IAMStreamSelect *iface, LONG index, DWORD flags)
Definition: mpegsplit.c:852
static int MPEGSplitter_head_check(const BYTE *header)
Definition: mpegsplit.c:83
#define MPEG_AUDIO_HEADER
Definition: mpegsplit.c:52
static HRESULT FillBuffer(MPEGSplitterImpl *This, IMediaSample *pCurrentSample)
Definition: mpegsplit.c:169
#define VIDEO_ELEMENTARY_STREAM
Definition: mpegsplit.c:48
#define PACK_START_CODE
Definition: mpegsplit.c:44
static HRESULT MPEGSplitter_disconnect(LPVOID iface)
Definition: mpegsplit.c:708
HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo)
Definition: parser.c:419
HRESULT WINAPI Parser_GetClassID(IBaseFilter *iface, CLSID *pClsid)
Definition: parser.c:228
HRESULT WINAPI Parser_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
Definition: parser.c:313
HRESULT WINAPI Parser_Pause(IBaseFilter *iface)
Definition: parser.c:279
HRESULT WINAPI Parser_Stop(IBaseFilter *iface)
Definition: parser.c:241
ULONG WINAPI Parser_AddRef(IBaseFilter *iface)
Definition: parser.c:171
HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo)
Definition: parser.c:429
HRESULT Parser_AddPin(ParserImpl *This, const PIN_INFO *piOutput, ALLOCATOR_PROPERTIES *props, const AM_MEDIA_TYPE *amt)
Definition: parser.c:446
HRESULT WINAPI Parser_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
Definition: parser.c:361
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
HRESULT WINAPI Parser_GetSyncSource(IBaseFilter *iface, IReferenceClock **ppClock)
Definition: parser.c:397
ULONG WINAPI Parser_Release(IBaseFilter *iface)
Definition: parser.c:213
HRESULT WINAPI Parser_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
Definition: parser.c:404
HRESULT WINAPI Parser_SetSyncSource(IBaseFilter *iface, IReferenceClock *pClock)
Definition: parser.c:383
HRESULT WINAPI Parser_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
Definition: parser.c:409
HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *pGraph, LPCWSTR pName)
Definition: parser.c:424
static Parser_OutputPin * unsafe_impl_Parser_OutputPin_from_IPin(IPin *iface)
Definition: parser.h:81
#define ALIGNUP(value, boundary)
Definition: pin.c:33
static WCHAR unknown[MAX_STRING_RESOURCE_LEN]
Definition: object.c:1605
#define assert(x)
Definition: debug.h:53
LONGLONG REFERENCE_TIME
Definition: dmusicks.h:9
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
size_t total
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLuint index
Definition: glext.h:6031
GLenum mode
Definition: glext.h:6217
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLboolean GLuint group
Definition: glext.h:11120
GLenum GLuint GLint GLint layer
Definition: glext.h:7007
GLenum GLsizei len
Definition: glext.h:6722
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
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:442
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:426
REFIID riid
Definition: atlbase.h:39
REFIID LPVOID * ppv
Definition: atlbase.h:39
Definition: axcore.idl:92
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define debugstr_guid
Definition: kernel32.h:35
__u16 time
Definition: mkdosfs.c:8
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define ACM_MPEG_DUALCHANNEL
Definition: mmreg.h:422
#define ACM_MPEG_STEREO
Definition: mmreg.h:420
#define MPEGLAYER3_FLAG_PADDING_ON
Definition: mmreg.h:446
#define ACM_MPEG_JOINTSTEREO
Definition: mmreg.h:421
#define MPEGLAYER3_ID_MPEG
Definition: mmreg.h:442
#define WAVE_FORMAT_MPEG
Definition: mmreg.h:126
#define MPEGLAYER3_WFX_EXTRA_BYTES
Definition: mmreg.h:439
#define WAVE_FORMAT_MPEGLAYER3
Definition: mmreg.h:127
#define ACM_MPEG_SINGLECHANNEL
Definition: mmreg.h:423
#define ACM_MPEG_LAYER3
Definition: mmreg.h:418
#define ACM_MPEG_LAYER1
Definition: mmreg.h:416
#define ACM_MPEG_LAYER2
Definition: mmreg.h:417
struct mpeg1waveformat_tag MPEG1WAVEFORMAT
#define ACM_MPEG_ID_MPEG1
Definition: mmreg.h:428
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
static const DWORD padding[]
Definition: mciwnd.c:89
unsigned int UINT
Definition: ndis.h:50
long LONG
Definition: pedump.c:60
static PullPin * impl_PullPin_from_IPin(IPin *iface)
Definition: pin.h:132
const GUID IID_IPin
Definition: pincontrol.cpp:15
const GUID IID_IPersist
Definition: proxy.cpp:14
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define REFIID
Definition: guiddef.h:118
void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *pmt)
Definition: enummedia.c:38
#define MEDIATIME_FROM_BYTES(x)
#define BYTES_FROM_MEDIATIME(time)
DWORD LCID
Definition: nls.h:13
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin *This, IMediaSample *pSample)
Definition: pin.c:574
BasePin pin
Definition: strmbase.h:66
double dRate
Definition: strmbase.h:43
IPin IPin_iface
Definition: strmbase.h:35
PIN_INFO pinInfo
Definition: strmbase.h:38
REFERENCE_TIME tStart
Definition: strmbase.h:41
LONGLONG position
Definition: mpegsplit.c:60
DWORD begin_offset
Definition: mpegsplit.c:61
IAMStreamSelect IAMStreamSelect_iface
Definition: mpegsplit.c:58
LONGLONG EndOfFile
Definition: mpegsplit.c:59
ParserImpl Parser
Definition: mpegsplit.c:57
BaseOutputPin pin
Definition: parser.h:46
Definition: pin.h:71
BasePin pin
Definition: pin.h:73
IAsyncReader * pReader
Definition: pin.h:77
Definition: cookie.c:34
DWORD dwHeadBitrate
Definition: mmreg.h:407
WORD fwHeadModeExt
Definition: mmreg.h:409
WORD wHeadEmphasis
Definition: mmreg.h:410
Definition: name.c:39
Definition: regsvr.c:104
uint32_t DWORD_PTR
Definition: typedefs.h:65
int64_t LONGLONG
Definition: typedefs.h:68
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define VFW_E_WRONG_STATE
Definition: vfwmsgs.h:78
static const WCHAR props[]
Definition: wbemdisp.c:288
#define ZeroMemory
Definition: winbase.h:1712
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:2357
#define E_NOINTERFACE
Definition: winerror.h:2364
#define CLASS_E_NOAGGREGATION
Definition: winerror.h:2662
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193