4 * Copyright 2003 Robert Shearman
5 * Copyright 2004-2005 Christian Costa
6 * Copyright 2007 Chris Robinson
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "quartz_private.h"
27 #include "control_private.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
43 #define SEQUENCE_HEADER_CODE 0xB3
44 #define PACK_START_CODE 0xBA
46 #define SYSTEM_START_CODE 0xBB
47 #define AUDIO_ELEMENTARY_STREAM 0xC0
48 #define VIDEO_ELEMENTARY_STREAM 0xE0
50 #define MPEG_SYSTEM_HEADER 3
51 #define MPEG_VIDEO_HEADER 2
52 #define MPEG_AUDIO_HEADER 1
53 #define MPEG_NO_HEADER 0
55 typedef struct MPEGSplitterImpl
58 IMediaSample
*pCurrentSample
;
60 DWORD dwSampleSize
, dwLength
;
64 static int MPEGSplitter_head_check(const BYTE
*header
)
66 /* If this is a possible start code, check for a system or video header */
67 if (header
[0] == 0 && header
[1] == 0 && header
[2] == 1)
69 /* Check if we got a system or elementary stream start code */
70 if (header
[3] == PACK_START_CODE
||
71 header
[3] == VIDEO_ELEMENTARY_STREAM
||
72 header
[3] == AUDIO_ELEMENTARY_STREAM
)
73 return MPEG_SYSTEM_HEADER
;
75 /* Check for a MPEG video sequence start code */
76 if (header
[3] == SEQUENCE_HEADER_CODE
)
77 return MPEG_VIDEO_HEADER
;
80 /* This should give a good guess if we have an MPEG audio header */
81 if(header
[0] == 0xff && ((header
[1]>>5)&0x7) == 0x7 &&
82 ((header
[1]>>1)&0x3) != 0 && ((header
[2]>>4)&0xf) != 0xf &&
83 ((header
[2]>>2)&0x3) != 0x3)
84 return MPEG_AUDIO_HEADER
;
87 return MPEG_NO_HEADER
;
91 static HRESULT
MPEGSplitter_process_sample(LPVOID iface
, IMediaSample
* pSample
)
93 MPEGSplitterImpl
*This
= (MPEGSplitterImpl
*)iface
;
94 LPBYTE pbSrcStream
= NULL
;
95 DWORD cbSrcStream
= 0;
97 REFERENCE_TIME tStart
, tStop
;
101 long remaining_bytes
= 0;
102 Parser_OutputPin
* pOutputPin
;
103 DWORD bytes_written
= 0;
105 pOutputPin
= (Parser_OutputPin
*)This
->Parser
.ppPins
[1];
107 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
110 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
111 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
114 /* trace removed for performance reasons */
115 /* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */
117 if (This
->pCurrentSample
)
118 bytes_written
= IMediaSample_GetActualDataLength(This
->pCurrentSample
);
120 while (hr
== S_OK
&& used_bytes
< cbSrcStream
)
122 remaining_bytes
= (long)(This
->EndOfFile
- BYTES_FROM_MEDIATIME(tStart
) - used_bytes
);
123 if (remaining_bytes
<= 0)
126 if (!This
->pCurrentSample
)
128 /* cache media sample until it is ready to be despatched
129 * (i.e. we reach the end of the chunk) */
130 hr
= OutputPin_GetDeliveryBuffer(&pOutputPin
->pin
, &This
->pCurrentSample
, NULL
, NULL
, 0);
133 TRACE("Skipping sending sample due to error (%x)\n", hr
);
134 This
->pCurrentSample
= NULL
;
138 IMediaSample_SetTime(This
->pCurrentSample
, NULL
, NULL
);
139 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, 0);
144 hr
= IMediaSample_GetPointer(This
->pCurrentSample
, &pbDstStream
);
147 cbDstStream
= IMediaSample_GetSize(This
->pCurrentSample
);
148 remaining_bytes
= min(remaining_bytes
, (long)(cbDstStream
- bytes_written
));
150 assert(remaining_bytes
>= 0);
152 /* trace removed for performance reasons */
153 /* TRACE("remaining_bytes: %d, cbSrcStream: 0x%x\n", remaining_bytes, cbSrcStream); */
156 if (remaining_bytes
<= (long)(cbSrcStream
-used_bytes
))
160 memcpy(pbDstStream
+ bytes_written
, pbSrcStream
+ used_bytes
, remaining_bytes
);
161 bytes_written
+= remaining_bytes
;
163 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, bytes_written
);
166 used_bytes
+= remaining_bytes
;
171 REFERENCE_TIME tMPEGStart
, tMPEGStop
;
173 pOutputPin
->dwSamplesProcessed
= (BYTES_FROM_MEDIATIME(tStart
)+used_bytes
) / This
->dwSampleSize
;
175 tMPEGStart
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
-bytes_written
)) /
176 (This
->fSamplesPerSec
*This
->dwSampleSize
);
177 tMPEGStop
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
)) /
178 (This
->fSamplesPerSec
*This
->dwSampleSize
);
180 /* If the start of the sample has a valid MPEG header, it's a
182 if (MPEGSplitter_head_check(pbDstStream
) == MPEG_AUDIO_HEADER
)
183 IMediaSample_SetSyncPoint(This
->pCurrentSample
, TRUE
);
185 IMediaSample_SetSyncPoint(This
->pCurrentSample
, FALSE
);
186 IMediaSample_SetTime(This
->pCurrentSample
, &tMPEGStart
, &tMPEGStop
);
188 hr
= OutputPin_SendSample(&pOutputPin
->pin
, This
->pCurrentSample
);
190 WARN("Error sending sample (%x)\n", hr
);
193 if (This
->pCurrentSample
)
194 IMediaSample_Release(This
->pCurrentSample
);
195 This
->pCurrentSample
= NULL
;
201 memcpy(pbDstStream
+ bytes_written
, pbSrcStream
+ used_bytes
, cbSrcStream
- used_bytes
);
202 bytes_written
+= cbSrcStream
- used_bytes
;
203 IMediaSample_SetActualDataLength(This
->pCurrentSample
, bytes_written
);
205 used_bytes
+= cbSrcStream
- used_bytes
;
210 if (BYTES_FROM_MEDIATIME(tStop
) >= This
->EndOfFile
)
214 TRACE("End of file reached (%d out of %d bytes used)\n", used_bytes
, cbSrcStream
);
216 if (This
->pCurrentSample
)
218 /* Make sure the last bit of data, if any, is sent */
219 if (IMediaSample_GetActualDataLength(This
->pCurrentSample
) > 0)
221 REFERENCE_TIME tMPEGStart
, tMPEGStop
;
223 pOutputPin
->dwSamplesProcessed
= (BYTES_FROM_MEDIATIME(tStart
)+used_bytes
) / This
->dwSampleSize
;
225 tMPEGStart
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
-bytes_written
)) /
226 (This
->fSamplesPerSec
*This
->dwSampleSize
);
227 tMPEGStop
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
)) /
228 (This
->fSamplesPerSec
*This
->dwSampleSize
);
230 if (MPEGSplitter_head_check(pbDstStream
) == MPEG_AUDIO_HEADER
)
231 IMediaSample_SetSyncPoint(This
->pCurrentSample
, TRUE
);
233 IMediaSample_SetSyncPoint(This
->pCurrentSample
, FALSE
);
234 IMediaSample_SetTime(This
->pCurrentSample
, &tMPEGStart
, &tMPEGStop
);
236 hr
= OutputPin_SendSample(&pOutputPin
->pin
, This
->pCurrentSample
);
238 WARN("Error sending sample (%x)\n", hr
);
240 IMediaSample_Release(This
->pCurrentSample
);
242 This
->pCurrentSample
= NULL
;
244 for (i
= 0; i
< This
->Parser
.cStreams
; i
++)
249 TRACE("Send End Of Stream to output pin %d\n", i
);
251 hr
= IPin_ConnectedTo(This
->Parser
.ppPins
[i
+1], &ppin
);
254 hr
= IPin_EndOfStream(ppin
);
258 WARN("Error sending EndOfStream to pin %d (%x)\n", i
, hr
);
261 /* Force the pullpin thread to stop */
269 static HRESULT
MPEGSplitter_query_accept(LPVOID iface
, const AM_MEDIA_TYPE
*pmt
)
271 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Stream
))
274 if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1Audio
))
277 if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1Video
))
278 FIXME("MPEG-1 video streams not yet supported.\n");
279 else if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1System
))
280 FIXME("MPEG-1 system streams not yet supported.\n");
281 else if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1VideoCD
))
282 FIXME("MPEG-1 VideoCD streams not yet supported.\n");
288 static const WCHAR wszAudioStream
[] = {'A','u','d','i','o',0};
289 static const WCHAR wszVideoStream
[] = {'V','i','d','e','o',0};
291 static HRESULT
MPEGSplitter_init_audio(MPEGSplitterImpl
*This
, const BYTE
*header
, PIN_INFO
*ppiOutput
, AM_MEDIA_TYPE
*pamt
)
293 static const DWORD freqs
[10] = { 44100, 48000, 32000, 22050, 24000,
294 16000, 11025, 12000, 8000, 0 };
295 static const DWORD tabsel_123
[2][3][16] = {
296 { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
297 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
298 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
300 { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
301 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
302 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
305 WAVEFORMATEX
*format
;
316 ZeroMemory(pamt
, sizeof(*pamt
));
317 ppiOutput
->dir
= PINDIR_OUTPUT
;
318 ppiOutput
->pFilter
= (IBaseFilter
*)This
;
319 wsprintfW(ppiOutput
->achName
, wszAudioStream
);
321 pamt
->formattype
= FORMAT_WaveFormatEx
;
322 pamt
->majortype
= MEDIATYPE_Audio
;
323 pamt
->subtype
= MEDIASUBTYPE_MPEG1AudioPayload
;
325 pamt
->lSampleSize
= 0;
326 pamt
->bFixedSizeSamples
= TRUE
;
327 pamt
->bTemporalCompression
= 0;
329 mpeg1
= (header
[1]>>4)&0x1;
331 lsf
= ((header
[1]>>3)&0x1)^1;
333 layer
= 4-((header
[1]>>1)&0x3);
334 bitrate_index
= ((header
[2]>>4)&0xf);
335 freq_index
= ((header
[2]>>2)&0x3) + (mpeg1
?(lsf
*3):6);
336 padding
= ((header
[2]>>1)&0x1);
337 mode
= ((header
[3]>>6)&0x3);
338 mode_ext
= ((header
[3]>>4)&0x3);
339 emphasis
= ((header
[3]>>0)&0x3);
341 pamt
->cbFormat
= ((layer
==3)? sizeof(MPEGLAYER3WAVEFORMAT
) :
342 sizeof(MPEG1WAVEFORMAT
));
343 pamt
->pbFormat
= CoTaskMemAlloc(pamt
->cbFormat
);
345 return E_OUTOFMEMORY
;
346 ZeroMemory(pamt
->pbFormat
, pamt
->cbFormat
);
347 format
= (WAVEFORMATEX
*)pamt
->pbFormat
;
349 format
->wFormatTag
= ((layer
== 3) ? WAVE_FORMAT_MPEGLAYER3
:
351 format
->nChannels
= ((mode
== 3) ? 1 : 2);
352 format
->nSamplesPerSec
= freqs
[freq_index
];
353 format
->nAvgBytesPerSec
= tabsel_123
[lsf
][layer
-1][bitrate_index
] * 1000 / 8;
354 if (format
->nAvgBytesPerSec
== 0)
356 WARN("Variable-bitrate audio is not supported.\n");
361 format
->nBlockAlign
= format
->nAvgBytesPerSec
* 8 * 144 /
362 (format
->nSamplesPerSec
<<lsf
) +
365 format
->nBlockAlign
= format
->nAvgBytesPerSec
* 8 * 144 /
366 format
->nSamplesPerSec
+ (padding
- 4);
368 format
->nBlockAlign
= ((format
->nAvgBytesPerSec
* 8 * 12 /
369 format
->nSamplesPerSec
+ padding
) << 2) - 4;
371 format
->wBitsPerSample
= 0;
375 MPEGLAYER3WAVEFORMAT
*mp3format
= (MPEGLAYER3WAVEFORMAT
*)format
;
377 format
->cbSize
= MPEGLAYER3_WFX_EXTRA_BYTES
;
379 mp3format
->wID
= MPEGLAYER3_ID_MPEG
;
380 mp3format
->fdwFlags
= (padding
?
381 MPEGLAYER3_FLAG_PADDING_OFF
:
382 MPEGLAYER3_FLAG_PADDING_ON
);
383 mp3format
->nBlockSize
= format
->nBlockAlign
;
384 mp3format
->nFramesPerBlock
= 1;
386 /* Beware the evil magic numbers. This struct is apparently horribly
387 * under-documented, and the only references I could find had it being
388 * set to this with no real explanation. It works fine though, so I'm
389 * not complaining (yet).
391 mp3format
->nCodecDelay
= 1393;
395 MPEG1WAVEFORMAT
*mpgformat
= (MPEG1WAVEFORMAT
*)format
;
399 mpgformat
->fwHeadLayer
= ((layer
== 1) ? ACM_MPEG_LAYER1
:
400 ((layer
== 2) ? ACM_MPEG_LAYER2
:
402 mpgformat
->dwHeadBitrate
= format
->nAvgBytesPerSec
* 8;
403 mpgformat
->fwHeadMode
= ((mode
== 3) ? ACM_MPEG_SINGLECHANNEL
:
404 ((mode
== 2) ? ACM_MPEG_DUALCHANNEL
:
405 ((mode
== 1) ? ACM_MPEG_JOINTSTEREO
:
407 mpgformat
->fwHeadModeExt
= ((mode
== 1) ? 0x0F : (1<<mode_ext
));
408 mpgformat
->wHeadEmphasis
= emphasis
+ 1;
409 mpgformat
->fwHeadFlags
= ACM_MPEG_ID_MPEG1
;
411 pamt
->subtype
.Data1
= format
->wFormatTag
;
413 TRACE("MPEG audio stream detected:\n"
416 "\tChannels: %d (%d)\n"
417 "\tBytesPerSec: %d\n",
418 layer
, format
->wFormatTag
, format
->nSamplesPerSec
,
419 format
->nChannels
, mode
, format
->nAvgBytesPerSec
);
421 dump_AM_MEDIA_TYPE(pamt
);
427 static HRESULT
MPEGSplitter_pre_connect(IPin
*iface
, IPin
*pConnectPin
)
429 PullPin
*pPin
= (PullPin
*)iface
;
430 MPEGSplitterImpl
*This
= (MPEGSplitterImpl
*)pPin
->pin
.pinInfo
.pFilter
;
431 ALLOCATOR_PROPERTIES props
;
433 LONGLONG pos
= 0; /* in bytes */
436 LONGLONG total
, avail
;
440 IAsyncReader_Length(pPin
->pReader
, &total
, &avail
);
441 This
->EndOfFile
= total
;
443 hr
= IAsyncReader_SyncRead(pPin
->pReader
, pos
, 4, header
);
447 /* Skip ID3 v2 tag, if any */
448 if (SUCCEEDED(hr
) && !strncmp("ID3", (char*)header
, 3))
451 hr
= IAsyncReader_SyncRead(pPin
->pReader
, pos
, 6, header
+ 4);
455 TRACE("Found ID3 v2.%d.%d\n", header
[3], header
[4]);
456 length
= (header
[6] & 0x7F) << 21;
457 length
+= (header
[7] & 0x7F) << 14;
458 length
+= (header
[8] & 0x7F) << 7;
459 length
+= (header
[9] & 0x7F);
460 TRACE("Length: %u\n", length
);
463 /* Read the real header for the mpeg splitter */
464 hr
= IAsyncReader_SyncRead(pPin
->pReader
, pos
, 4, header
);
467 TRACE("%x:%x:%x:%x\n", header
[0], header
[1], header
[2], header
[3]);
470 while(SUCCEEDED(hr
) && !(streamtype
=MPEGSplitter_head_check(header
)))
472 TRACE("%x:%x:%x:%x\n", header
[0], header
[1], header
[2], header
[3]);
473 /* No valid header yet; shift by a byte and check again */
474 memcpy(header
, header
+1, 3);
475 hr
= IAsyncReader_SyncRead(pPin
->pReader
, pos
++, 1, header
+ 3);
482 case MPEG_AUDIO_HEADER
:
483 hr
= MPEGSplitter_init_audio(This
, header
, &piOutput
, &amt
);
486 WAVEFORMATEX
*format
= (WAVEFORMATEX
*)amt
.pbFormat
;
490 /* Make the output buffer a multiple of the frame size */
491 props
.cbBuffer
= 0x4000 / format
->nBlockAlign
*
494 This
->fSamplesPerSec
= (float)format
->nAvgBytesPerSec
/ (float)format
->nBlockAlign
;
495 This
->dwSampleSize
= format
->nBlockAlign
;
496 This
->dwLength
= total
;
497 hr
= Parser_AddPin(&(This
->Parser
), &piOutput
, &props
, &amt
);
503 CoTaskMemFree(amt
.pbFormat
);
504 ERR("Could not create pin for MPEG audio stream (%x)\n", hr
);
507 case MPEG_VIDEO_HEADER
:
508 FIXME("MPEG video processing not yet supported!\n");
511 case MPEG_SYSTEM_HEADER
:
512 FIXME("MPEG system streams not yet supported!\n");
523 static HRESULT
MPEGSplitter_cleanup(LPVOID iface
)
525 MPEGSplitterImpl
*This
= (MPEGSplitterImpl
*)iface
;
527 TRACE("(%p)->()\n", This
);
529 if (This
->pCurrentSample
)
530 IMediaSample_Release(This
->pCurrentSample
);
531 This
->pCurrentSample
= NULL
;
536 HRESULT
MPEGSplitter_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
538 MPEGSplitterImpl
*This
;
541 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
546 return CLASS_E_NOAGGREGATION
;
548 This
= CoTaskMemAlloc(sizeof(MPEGSplitterImpl
));
550 return E_OUTOFMEMORY
;
552 ZeroMemory(This
, sizeof(MPEGSplitterImpl
));
553 hr
= Parser_Create(&(This
->Parser
), &CLSID_MPEG1Splitter
, MPEGSplitter_process_sample
, MPEGSplitter_query_accept
, MPEGSplitter_pre_connect
, MPEGSplitter_cleanup
);
560 /* Note: This memory is managed by the parser filter once created */