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
56 typedef struct MPEGSplitterImpl
59 IMediaSample
*pCurrentSample
;
63 static int MPEGSplitter_head_check(const BYTE
*header
)
65 /* If this is a possible start code, check for a system or video header */
66 if (header
[0] == 0 && header
[1] == 0 && header
[2] == 1)
68 /* Check if we got a system or elementary stream start code */
69 if (header
[3] == PACK_START_CODE
||
70 header
[3] == VIDEO_ELEMENTARY_STREAM
||
71 header
[3] == AUDIO_ELEMENTARY_STREAM
)
72 return MPEG_SYSTEM_HEADER
;
74 /* Check for a MPEG video sequence start code */
75 if (header
[3] == SEQUENCE_HEADER_CODE
)
76 return MPEG_VIDEO_HEADER
;
79 /* This should give a good guess if we have an MPEG audio header */
80 if(header
[0] == 0xff && ((header
[1]>>5)&0x7) == 0x7 &&
81 ((header
[1]>>1)&0x3) != 0 && ((header
[2]>>4)&0xf) != 0xf &&
82 ((header
[2]>>2)&0x3) != 0x3)
83 return MPEG_AUDIO_HEADER
;
86 return MPEG_NO_HEADER
;
90 static HRESULT
MPEGSplitter_process_sample(LPVOID iface
, IMediaSample
* pSample
)
92 MPEGSplitterImpl
*This
= (MPEGSplitterImpl
*)iface
;
93 LPBYTE pbSrcStream
= NULL
;
94 DWORD cbSrcStream
= 0;
96 REFERENCE_TIME tStart
, tStop
;
100 long remaining_bytes
= 0;
101 Parser_OutputPin
* pOutputPin
;
102 DWORD bytes_written
= 0;
104 pOutputPin
= (Parser_OutputPin
*)This
->Parser
.ppPins
[1];
106 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
109 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
110 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
113 /* trace removed for performance reasons */
114 /* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */
116 if (This
->pCurrentSample
)
117 bytes_written
= IMediaSample_GetActualDataLength(This
->pCurrentSample
);
119 while (hr
== S_OK
&& used_bytes
< cbSrcStream
)
121 remaining_bytes
= (long)(This
->EndOfFile
- BYTES_FROM_MEDIATIME(tStart
) - used_bytes
);
122 if (remaining_bytes
<= 0)
125 if (!This
->pCurrentSample
)
127 /* cache media sample until it is ready to be despatched
128 * (i.e. we reach the end of the chunk) */
129 hr
= OutputPin_GetDeliveryBuffer(&pOutputPin
->pin
, &This
->pCurrentSample
, NULL
, NULL
, 0);
132 TRACE("Skipping sending sample due to error (%x)\n", hr
);
133 This
->pCurrentSample
= NULL
;
137 IMediaSample_SetTime(This
->pCurrentSample
, NULL
, NULL
);
138 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, 0);
143 hr
= IMediaSample_GetPointer(This
->pCurrentSample
, &pbDstStream
);
146 cbDstStream
= IMediaSample_GetSize(This
->pCurrentSample
);
147 remaining_bytes
= min(remaining_bytes
, (long)(cbDstStream
- bytes_written
));
149 assert(remaining_bytes
>= 0);
151 /* trace removed for performance reasons */
152 /* TRACE("remaining_bytes: %d, cbSrcStream: 0x%x\n", remaining_bytes, cbSrcStream); */
155 if (remaining_bytes
<= (long)(cbSrcStream
-used_bytes
))
159 memcpy(pbDstStream
+ bytes_written
, pbSrcStream
+ used_bytes
, remaining_bytes
);
160 bytes_written
+= remaining_bytes
;
162 hr
= IMediaSample_SetActualDataLength(This
->pCurrentSample
, bytes_written
);
165 used_bytes
+= remaining_bytes
;
170 REFERENCE_TIME tMPEGStart
, tMPEGStop
;
172 pOutputPin
->dwSamplesProcessed
= (BYTES_FROM_MEDIATIME(tStart
)+used_bytes
) / pOutputPin
->dwSampleSize
;
174 tMPEGStart
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
-bytes_written
)) /
175 (pOutputPin
->fSamplesPerSec
*pOutputPin
->dwSampleSize
);
176 tMPEGStop
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
)) /
177 (pOutputPin
->fSamplesPerSec
*pOutputPin
->dwSampleSize
);
179 /* If the start of the sample has a valid MPEG header, it's a
181 if (MPEGSplitter_head_check(pbDstStream
) == MPEG_AUDIO_HEADER
)
182 IMediaSample_SetSyncPoint(This
->pCurrentSample
, TRUE
);
184 IMediaSample_SetSyncPoint(This
->pCurrentSample
, FALSE
);
185 IMediaSample_SetTime(This
->pCurrentSample
, &tMPEGStart
, &tMPEGStop
);
187 hr
= OutputPin_SendSample(&pOutputPin
->pin
, This
->pCurrentSample
);
189 WARN("Error sending sample (%x)\n", hr
);
192 if (This
->pCurrentSample
)
193 IMediaSample_Release(This
->pCurrentSample
);
194 This
->pCurrentSample
= NULL
;
200 memcpy(pbDstStream
+ bytes_written
, pbSrcStream
+ used_bytes
, cbSrcStream
- used_bytes
);
201 bytes_written
+= cbSrcStream
- used_bytes
;
202 IMediaSample_SetActualDataLength(This
->pCurrentSample
, bytes_written
);
204 used_bytes
+= cbSrcStream
- used_bytes
;
209 if (BYTES_FROM_MEDIATIME(tStop
) >= This
->EndOfFile
)
213 TRACE("End of file reached (%d out of %d bytes used)\n", used_bytes
, cbSrcStream
);
215 if (This
->pCurrentSample
)
217 /* Make sure the last bit of data, if any, is sent */
218 if (IMediaSample_GetActualDataLength(This
->pCurrentSample
) > 0)
220 REFERENCE_TIME tMPEGStart
, tMPEGStop
;
222 pOutputPin
->dwSamplesProcessed
= (BYTES_FROM_MEDIATIME(tStart
)+used_bytes
) / pOutputPin
->dwSampleSize
;
224 tMPEGStart
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
-bytes_written
)) /
225 (pOutputPin
->fSamplesPerSec
*pOutputPin
->dwSampleSize
);
226 tMPEGStop
= (tStart
+ MEDIATIME_FROM_BYTES(used_bytes
)) /
227 (pOutputPin
->fSamplesPerSec
*pOutputPin
->dwSampleSize
);
229 if (MPEGSplitter_head_check(pbDstStream
) == MPEG_AUDIO_HEADER
)
230 IMediaSample_SetSyncPoint(This
->pCurrentSample
, TRUE
);
232 IMediaSample_SetSyncPoint(This
->pCurrentSample
, FALSE
);
233 IMediaSample_SetTime(This
->pCurrentSample
, &tMPEGStart
, &tMPEGStop
);
235 hr
= OutputPin_SendSample(&pOutputPin
->pin
, This
->pCurrentSample
);
237 WARN("Error sending sample (%x)\n", hr
);
239 IMediaSample_Release(This
->pCurrentSample
);
241 This
->pCurrentSample
= NULL
;
243 for (i
= 0; i
< This
->Parser
.cStreams
; i
++)
248 TRACE("Send End Of Stream to output pin %d\n", i
);
250 hr
= IPin_ConnectedTo(This
->Parser
.ppPins
[i
+1], &ppin
);
253 hr
= IPin_EndOfStream(ppin
);
257 WARN("Error sending EndOfStream to pin %d (%x)\n", i
, hr
);
260 /* Force the pullpin thread to stop */
268 static HRESULT
MPEGSplitter_query_accept(LPVOID iface
, const AM_MEDIA_TYPE
*pmt
)
270 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Stream
))
273 if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1Audio
))
276 if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1Video
))
277 FIXME("MPEG-1 video streams not yet supported.\n");
278 else if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1System
))
279 FIXME("MPEG-1 system streams not yet supported.\n");
280 else if (IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_MPEG1VideoCD
))
281 FIXME("MPEG-1 VideoCD streams not yet supported.\n");
287 static const WCHAR wszAudioStream
[] = {'A','u','d','i','o',0};
288 static const WCHAR wszVideoStream
[] = {'V','i','d','e','o',0};
290 static HRESULT
MPEGSplitter_init_audio(MPEGSplitterImpl
*This
, const BYTE
*header
, PIN_INFO
*ppiOutput
, AM_MEDIA_TYPE
*pamt
)
292 static const DWORD freqs
[10] = { 44100, 48000, 32000, 22050, 24000,
293 16000, 11025, 12000, 8000, 0 };
294 static const DWORD tabsel_123
[2][3][16] = {
295 { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
296 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
297 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
299 { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
300 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
301 {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
304 WAVEFORMATEX
*format
;
315 ZeroMemory(pamt
, sizeof(*pamt
));
316 ppiOutput
->dir
= PINDIR_OUTPUT
;
317 ppiOutput
->pFilter
= (IBaseFilter
*)This
;
318 wsprintfW(ppiOutput
->achName
, wszAudioStream
);
320 memcpy(&pamt
->formattype
, &FORMAT_WaveFormatEx
, sizeof(GUID
));
321 memcpy(&pamt
->majortype
, &MEDIATYPE_Audio
, sizeof(GUID
));
322 memcpy(&pamt
->subtype
, &MEDIASUBTYPE_MPEG1AudioPayload
, sizeof(GUID
));
324 pamt
->lSampleSize
= 0;
325 pamt
->bFixedSizeSamples
= TRUE
;
326 pamt
->bTemporalCompression
= 0;
328 mpeg1
= (header
[1]>>4)&0x1;
330 lsf
= ((header
[1]>>3)&0x1)^1;
332 layer
= 4-((header
[1]>>1)&0x3);
333 bitrate_index
= ((header
[2]>>4)&0xf);
334 freq_index
= ((header
[2]>>2)&0x3) + (mpeg1
?(lsf
*3):6);
335 padding
= ((header
[2]>>1)&0x1);
336 mode
= ((header
[3]>>6)&0x3);
337 mode_ext
= ((header
[3]>>4)&0x3);
338 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, (LPVOID
)&header
[0]);
447 while(SUCCEEDED(hr
) && !(streamtype
=MPEGSplitter_head_check(header
)))
449 /* No valid header yet; shift by a byte and check again */
450 memcpy(header
, header
+1, 3);
451 hr
= IAsyncReader_SyncRead(pPin
->pReader
, pos
++, 1, (LPVOID
)&header
[3]);
458 case MPEG_AUDIO_HEADER
:
459 hr
= MPEGSplitter_init_audio(This
, header
, &piOutput
, &amt
);
462 WAVEFORMATEX
*format
= (WAVEFORMATEX
*)amt
.pbFormat
;
466 /* Make the output buffer a multiple of the frame size */
467 props
.cbBuffer
= 0x4000 / format
->nBlockAlign
*
471 hr
= Parser_AddPin(&(This
->Parser
), &piOutput
, &props
, &amt
,
472 (float)format
->nAvgBytesPerSec
/
473 (float)format
->nBlockAlign
,
481 CoTaskMemFree(amt
.pbFormat
);
482 ERR("Could not create pin for MPEG audio stream (%x)\n", hr
);
485 case MPEG_VIDEO_HEADER
:
486 FIXME("MPEG video processing not yet supported!\n");
489 case MPEG_SYSTEM_HEADER
:
490 FIXME("MPEG system streams not yet supported!\n");
501 static HRESULT
MPEGSplitter_cleanup(LPVOID iface
)
503 MPEGSplitterImpl
*This
= (MPEGSplitterImpl
*)iface
;
505 TRACE("(%p)->()\n", This
);
507 if (This
->pCurrentSample
)
508 IMediaSample_Release(This
->pCurrentSample
);
509 This
->pCurrentSample
= NULL
;
514 HRESULT
MPEGSplitter_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
516 MPEGSplitterImpl
*This
;
519 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
524 return CLASS_E_NOAGGREGATION
;
526 This
= CoTaskMemAlloc(sizeof(MPEGSplitterImpl
));
528 return E_OUTOFMEMORY
;
530 ZeroMemory(This
, sizeof(MPEGSplitterImpl
));
531 hr
= Parser_Create(&(This
->Parser
), &CLSID_MPEG1Splitter
, MPEGSplitter_process_sample
, MPEGSplitter_query_accept
, MPEGSplitter_pre_connect
, MPEGSplitter_cleanup
);
538 /* Note: This memory is managed by the parser filter once created */