Parent Directory | Revision Log
Revision 2045 - (view) (download)
1 : | Irhall | 2014 | /***************************************************************************** |
2 : | * | ||
3 : | * Xvid MiniConvert | ||
4 : | * - Helper filters - | ||
5 : | * | ||
6 : | * Copyright(C) 2011 Xvid Solutions GmbH | ||
7 : | * | ||
8 : | * This program is free software ; you can redistribute it and/or modify | ||
9 : | * it under the terms of the GNU General Public License as published by | ||
10 : | * the Free Software Foundation ; either version 2 of the License, or | ||
11 : | * (at your option) any later version. | ||
12 : | * | ||
13 : | * This program 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 | ||
16 : | * GNU General Public License for more details. | ||
17 : | * | ||
18 : | * You should have received a copy of the GNU General Public License | ||
19 : | * along with this program ; if not, write to the Free Software | ||
20 : | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 : | * | ||
22 : | * $Id$ | ||
23 : | * | ||
24 : | ****************************************************************************/ | ||
25 : | /* | ||
26 : | * Author(s): Ireneusz Hallmann | ||
27 : | * | ||
28 : | ****************************************************************************/ | ||
29 : | |||
30 : | #include "stdafx.h" | ||
31 : | #include "filters.h" | ||
32 : | #include "mmreg.h" // WAVE_FORMAT_MPEGLAYER3 format structure | ||
33 : | |||
34 : | ////////////////////////////////////////////////////////////////////////////////////////////////// | ||
35 : | |||
36 : | CUnknown * WINAPI | ||
37 : | CProgressNotifyFilter::CreateInstance(IUnknown *pUnk, HRESULT *phr, int Type) | ||
38 : | { | ||
39 : | CUnknown *pNewFilter = new CProgressNotifyFilter(pUnk, phr, Type); | ||
40 : | |||
41 : | if (phr) { | ||
42 : | if (pNewFilter == NULL) *phr = E_OUTOFMEMORY; | ||
43 : | else *phr = S_OK; | ||
44 : | } | ||
45 : | |||
46 : | return pNewFilter; | ||
47 : | } | ||
48 : | |||
49 : | CProgressNotifyFilter::CProgressNotifyFilter(LPUNKNOWN pUnk, HRESULT *phr, int Type) : | ||
50 : | CTransInPlaceFilter("ProgressNotify", pUnk, CLSID_ProgressNotifyFilter, phr, false) | ||
51 : | { | ||
52 : | m_MessageWnd = 0; | ||
53 : | m_SampleCnt = 0; | ||
54 : | m_Pass = 1; | ||
55 : | m_Type = Type; | ||
56 : | m_startTime = 0; | ||
57 : | m_stopTime = 0; | ||
58 : | m_Width = 0, m_Height = 0; | ||
59 : | m_AvgTimeForFrame = 0; | ||
60 : | |||
61 : | if (*phr) *phr = S_OK; | ||
62 : | } | ||
63 : | |||
64 : | |||
65 : | CProgressNotifyFilter::~CProgressNotifyFilter(void) | ||
66 : | { | ||
67 : | } | ||
68 : | |||
69 : | HRESULT | ||
70 : | CProgressNotifyFilter::NonDelegatingQueryInterface(REFIID riid, void ** ppv) | ||
71 : | { | ||
72 : | if (riid == IID_IRecProgressNotify) | ||
73 : | return GetInterface((IRecProgressNotify*)this, ppv); | ||
74 : | |||
75 : | return CBaseFilter::NonDelegatingQueryInterface (riid, ppv); | ||
76 : | } | ||
77 : | |||
78 : | HRESULT | ||
79 : | CProgressNotifyFilter::CheckInputType(const CMediaType *mtIn) | ||
80 : | { | ||
81 : | if (mtIn->majortype != MEDIATYPE_Video && | ||
82 : | mtIn->majortype != MEDIATYPE_Audio) { | ||
83 : | |||
84 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
85 : | } | ||
86 : | |||
87 : | if (mtIn->formattype != FORMAT_None) { | ||
88 : | |||
89 : | if (mtIn->formattype == FORMAT_VideoInfo || | ||
90 : | mtIn->formattype == FORMAT_MPEGVideo) { | ||
91 : | |||
92 : | m_AvgTimeForFrame = ((VIDEOINFOHEADER *)mtIn->pbFormat)->AvgTimePerFrame; | ||
93 : | m_Width = ((VIDEOINFOHEADER *)mtIn->pbFormat)->bmiHeader.biWidth; | ||
94 : | m_Height = ((VIDEOINFOHEADER *)mtIn->pbFormat)->bmiHeader.biHeight; | ||
95 : | |||
96 : | } | ||
97 : | else if (mtIn->formattype == FORMAT_VideoInfo2 || | ||
98 : | mtIn->formattype == FORMAT_MPEG2Video) { | ||
99 : | |||
100 : | m_AvgTimeForFrame = ((VIDEOINFOHEADER2 *)mtIn->pbFormat)->AvgTimePerFrame; | ||
101 : | m_Width = ((VIDEOINFOHEADER2 *)mtIn->pbFormat)->bmiHeader.biWidth; | ||
102 : | m_Height = ((VIDEOINFOHEADER2 *)mtIn->pbFormat)->bmiHeader.biHeight; | ||
103 : | |||
104 : | } | ||
105 : | else if (mtIn->formattype == FORMAT_WaveFormatEx && m_Type == 2) { | ||
106 : | |||
107 : | MPEGLAYER3WAVEFORMAT *pMp3 = (MPEGLAYER3WAVEFORMAT *)mtIn->pbFormat; | ||
108 : | Isibaar | 2045 | if (pMp3->wfx.nChannels >= 2 && pMp3->wfx.nAvgBytesPerSec != m_AudioBitrate) |
109 : | Irhall | 2014 | return VFW_E_TYPE_NOT_ACCEPTED; |
110 : | } | ||
111 : | else if (m_Type == 0) { | ||
112 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
113 : | } | ||
114 : | } | ||
115 : | |||
116 : | return S_OK; | ||
117 : | } | ||
118 : | |||
119 : | HRESULT | ||
120 : | CProgressNotifyFilter::Transform(IMediaSample *pSample) | ||
121 : | { | ||
122 : | LONGLONG osTime, sTime, eTime; | ||
123 : | pSample->GetTime(&osTime, &eTime); | ||
124 : | sTime = osTime; | ||
125 : | int bSetTime = 0; | ||
126 : | Isibaar | 2045 | DWORD SamplesSize = pSample->GetActualDataLength(); |
127 : | Irhall | 2014 | |
128 : | if (m_Type == 0) { // Video | ||
129 : | |||
130 : | #if 0 // emms instruction - for debug | ||
131 : | #ifdef __FUNCTION__ | ||
132 : | // Visual Studio | ||
133 : | __asm emms; | ||
134 : | #else | ||
135 : | __asm ("emms"); | ||
136 : | #endif | ||
137 : | #endif | ||
138 : | |||
139 : | m_TotalDataSize += pSample->GetActualDataLength(); | ||
140 : | m_SampleCnt++; | ||
141 : | |||
142 : | int CurPos = (int) (m_TotalFrames ? (((double)(100 * m_SampleCnt/m_TotalFrames) + 0.5)) : 0); | ||
143 : | |||
144 : | if (m_Pass == 0) { | ||
145 : | CurPos /= 2; | ||
146 : | } | ||
147 : | else if (m_Pass == 2) { | ||
148 : | CurPos = CurPos/2 + 50; | ||
149 : | } | ||
150 : | |||
151 : | if (m_totalSize > 0) { | ||
152 : | CurPos = ((CurPos*m_curSize) / m_totalSize); | ||
153 : | CurPos += ((100*m_elapsedSize) / m_totalSize); | ||
154 : | } | ||
155 : | |||
156 : | if (m_MessageWnd) | ||
157 : | PostMessage(m_MessageWnd, PBM_SETPOS, CurPos, 0); | ||
158 : | } | ||
159 : | else { // Audio | ||
160 : | MPEGLAYER3WAVEFORMAT *pMp3 = 0; | ||
161 : | |||
162 : | if (m_MediaType.subtype == MEDIASUBTYPE_MP3) { | ||
163 : | pMp3 = (MPEGLAYER3WAVEFORMAT *)m_MediaType.pbFormat; | ||
164 : | |||
165 : | Isibaar | 2045 | DWORD ThisSamples = (pMp3->wfx.nSamplesPerSec >= 32000 ? 1152 : 576) * pMp3->nFramesPerBlock; |
166 : | Irhall | 2014 | |
167 : | LONGLONG sDuration = eTime - sTime; | ||
168 : | if (((m_SampleCnt || sTime) && sTime <= m_stopTime)) { | ||
169 : | sTime = m_stopTime + 1; | ||
170 : | bSetTime = 1; | ||
171 : | } | ||
172 : | if (eTime <= sTime || sDuration != (ThisSamples * 10000000LL * m_FpsDen)/m_FpsNom) { | ||
173 : | sDuration = (ThisSamples * 10000000LL * m_FpsDen)/m_FpsNom - 1; | ||
174 : | eTime = sTime + sDuration; | ||
175 : | bSetTime = 1; | ||
176 : | } | ||
177 : | sTime = osTime; //!! | ||
178 : | Isibaar | 2045 | m_SampleCnt += ThisSamples; |
179 : | Irhall | 2014 | |
180 : | pSample->SetSyncPoint(TRUE); | ||
181 : | } | ||
182 : | } | ||
183 : | |||
184 : | if (bSetTime) | ||
185 : | pSample->SetTime(&sTime, &eTime); | ||
186 : | |||
187 : | m_startTime = sTime; | ||
188 : | m_stopTime = eTime; | ||
189 : | |||
190 : | return S_OK; | ||
191 : | } | ||
192 : | |||
193 : | HRESULT | ||
194 : | CProgressNotifyFilter::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) | ||
195 : | { | ||
196 : | HRESULT hr = pReceivePin->ConnectionMediaType(&m_MediaType); | ||
197 : | m_MinSampleSize = 0; | ||
198 : | |||
199 : | if (hr == S_OK) { | ||
200 : | if (m_MediaType.formattype == FORMAT_VideoInfo | ||
201 : | || m_MediaType.formattype == FORMAT_MPEGVideo) { | ||
202 : | |||
203 : | m_AvgTimeForFrame = ((VIDEOINFOHEADER *)m_MediaType.pbFormat)->AvgTimePerFrame; | ||
204 : | |||
205 : | if (direction == PINDIR_INPUT) { | ||
206 : | if (m_MediaType.bTemporalCompression || m_MediaType.lSampleSize <=1) { | ||
207 : | m_MinSampleSize = ((VIDEOINFOHEADER *)m_MediaType.pbFormat)->bmiHeader.biHeight * | ||
208 : | ((VIDEOINFOHEADER *)m_MediaType.pbFormat)->bmiHeader.biWidth * 4; | ||
209 : | } | ||
210 : | } | ||
211 : | } | ||
212 : | else if (m_MediaType.formattype == FORMAT_VideoInfo2 || | ||
213 : | m_MediaType.formattype == FORMAT_MPEG2Video) { | ||
214 : | m_AvgTimeForFrame = ((VIDEOINFOHEADER2 *)m_MediaType.pbFormat)->AvgTimePerFrame; | ||
215 : | |||
216 : | if (direction == PINDIR_INPUT) { | ||
217 : | if (m_MediaType.bTemporalCompression || m_MediaType.lSampleSize <=1) { | ||
218 : | m_MinSampleSize = ((VIDEOINFOHEADER2 *)m_MediaType.pbFormat)->bmiHeader.biHeight * | ||
219 : | ((VIDEOINFOHEADER2 *)m_MediaType.pbFormat)->bmiHeader.biWidth * 4; | ||
220 : | } | ||
221 : | } | ||
222 : | } | ||
223 : | else if (m_Type == 0) { | ||
224 : | hr = VFW_E_TYPE_NOT_ACCEPTED; | ||
225 : | } | ||
226 : | |||
227 : | if (m_AvgTimeForFrame) { | ||
228 : | |||
229 : | switch (m_AvgTimeForFrame) { | ||
230 : | case 416666: // 24.0 FPS | ||
231 : | m_FpsNom = 24; | ||
232 : | m_FpsDen = 1; | ||
233 : | break; | ||
234 : | |||
235 : | case 417083: // 23.97 FPS | ||
236 : | m_FpsNom = 24000; | ||
237 : | m_FpsDen = 1001; | ||
238 : | break; | ||
239 : | |||
240 : | case 333333: // 30.0 FPS | ||
241 : | m_FpsNom = 30; | ||
242 : | m_FpsDen = 1; | ||
243 : | break; | ||
244 : | |||
245 : | case 333666: // 29.97 FPS | ||
246 : | m_FpsNom = 30000; | ||
247 : | m_FpsDen = 1001; | ||
248 : | break; | ||
249 : | |||
250 : | default: | ||
251 : | m_FpsNom = (int) (10000000 / m_AvgTimeForFrame); | ||
252 : | m_FpsDen = 1; | ||
253 : | } | ||
254 : | } | ||
255 : | else if (m_Type == 1 || m_Type == 2) { | ||
256 : | WAVEFORMATEX *pWave = (WAVEFORMATEX *)m_MediaType.pbFormat; | ||
257 : | m_FpsNom = pWave->nSamplesPerSec; | ||
258 : | m_FpsDen = 1; | ||
259 : | } | ||
260 : | } | ||
261 : | |||
262 : | return hr; | ||
263 : | } | ||
264 : | |||
265 : | HRESULT | ||
266 : | CProgressNotifyFilter::DecideBufferSize(IMemAllocator *pAlloc, | ||
267 : | ALLOCATOR_PROPERTIES *pProperties) | ||
268 : | { | ||
269 : | ALLOCATOR_PROPERTIES Request, Actual; | ||
270 : | HRESULT hr; | ||
271 : | |||
272 : | // If we are connected upstream, get his views | ||
273 : | if (m_pInput->IsConnected()) { | ||
274 : | // Get the input pin allocator, and get its size and count. | ||
275 : | // we don't care about his alignment and prefix. | ||
276 : | |||
277 : | hr = InputPin()->PeekAllocator()->GetProperties(&Request); | ||
278 : | |||
279 : | if (FAILED(hr)) { | ||
280 : | // Input connected but with a secretive allocator - enough! | ||
281 : | return hr; | ||
282 : | } | ||
283 : | |||
284 : | if (m_MinSampleSize && (m_Type == 0)) { | ||
285 : | if (Request.cbBuffer < m_MinSampleSize) { | ||
286 : | Request.cbBuffer = m_MinSampleSize; | ||
287 : | } | ||
288 : | } | ||
289 : | } | ||
290 : | else { | ||
291 : | // We're reduced to blind guessing. Let's guess one byte and if | ||
292 : | // this isn't enough then when the other pin does get connected | ||
293 : | // we can revise it. | ||
294 : | |||
295 : | ZeroMemory(&Request, sizeof(Request)); | ||
296 : | Request.cBuffers = 1; | ||
297 : | Request.cbBuffer = 1; | ||
298 : | } | ||
299 : | |||
300 : | #ifdef _DEBUG | ||
301 : | DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); | ||
302 : | DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), Request.cBuffers, Request.cbBuffer)); | ||
303 : | #endif | ||
304 : | |||
305 : | // Pass the allocator requirements to our output side | ||
306 : | // but do a little sanity checking first or we'll just hit | ||
307 : | // asserts in the allocator. | ||
308 : | |||
309 : | pProperties->cBuffers = Request.cBuffers; | ||
310 : | pProperties->cbBuffer = Request.cbBuffer; | ||
311 : | pProperties->cbAlign = Request.cbAlign; | ||
312 : | |||
313 : | if (pProperties->cBuffers<=0) { | ||
314 : | pProperties->cBuffers = 1; | ||
315 : | } | ||
316 : | |||
317 : | if (pProperties->cbBuffer<=0) { | ||
318 : | pProperties->cbBuffer = 1; | ||
319 : | } | ||
320 : | |||
321 : | hr = pAlloc->SetProperties(pProperties, &Actual); | ||
322 : | if (FAILED(hr)) { | ||
323 : | return hr; | ||
324 : | } | ||
325 : | |||
326 : | #ifdef _DEBUG | ||
327 : | DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); | ||
328 : | DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), | ||
329 : | Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); | ||
330 : | #endif | ||
331 : | |||
332 : | // Make sure we got the right alignment and at least the minimum required | ||
333 : | if ((Request.cBuffers > Actual.cBuffers) || | ||
334 : | (Request.cbBuffer > Actual.cbBuffer) || | ||
335 : | (Request.cbAlign > Actual.cbAlign)) | ||
336 : | { | ||
337 : | return E_FAIL; | ||
338 : | } | ||
339 : | |||
340 : | return NOERROR; | ||
341 : | } | ||
342 : | |||
343 : | ////////////////////////////////////////////////////////////////////////////////////////// | ||
344 : | |||
345 : | HRESULT | ||
346 : | CIRecProgressNotify::GetDimensions(DWORD &Width, DWORD &Height) | ||
347 : | { | ||
348 : | Width = m_Width; | ||
349 : | Height = m_Height; | ||
350 : | |||
351 : | return S_OK; | ||
352 : | } | ||
353 : | |||
354 : | HRESULT | ||
355 : | CIRecProgressNotify::GetBitrate(DWORD &OutFramesCount, | ||
356 : | LONGLONG &OutTotalDataSize) | ||
357 : | { | ||
358 : | OutFramesCount = m_SampleCnt; | ||
359 : | OutTotalDataSize = m_TotalDataSize; | ||
360 : | |||
361 : | return S_OK; | ||
362 : | } | ||
363 : | |||
364 : | HRESULT | ||
365 : | CIRecProgressNotify::SetPass(int in_Pass) | ||
366 : | { | ||
367 : | m_Pass = in_Pass; | ||
368 : | m_SampleCnt = 0; | ||
369 : | |||
370 : | return S_OK; | ||
371 : | } | ||
372 : | |||
373 : | HRESULT | ||
374 : | CIRecProgressNotify::SetTotalFrames(DWORD in_TotalFrames) | ||
375 : | { | ||
376 : | m_TotalFrames = in_TotalFrames; | ||
377 : | |||
378 : | return S_OK; | ||
379 : | } | ||
380 : | |||
381 : | HRESULT | ||
382 : | CIRecProgressNotify::SetNotifyWnd(HWND in_hWnd) | ||
383 : | { | ||
384 : | m_MessageWnd = in_hWnd; | ||
385 : | |||
386 : | return S_OK; | ||
387 : | } | ||
388 : | |||
389 : | STDMETHODIMP | ||
390 : | CIRecProgressNotify::SetTotalSize(int nbTotal) | ||
391 : | { | ||
392 : | m_totalSize = nbTotal; | ||
393 : | |||
394 : | return S_OK; | ||
395 : | } | ||
396 : | |||
397 : | STDMETHODIMP | ||
398 : | CIRecProgressNotify::SetCurSize(int nbCur) | ||
399 : | { | ||
400 : | m_curSize = nbCur; | ||
401 : | |||
402 : | return S_OK; | ||
403 : | } | ||
404 : | |||
405 : | STDMETHODIMP | ||
406 : | CIRecProgressNotify::SetElapsedSize(int nbElapsed) | ||
407 : | { | ||
408 : | m_elapsedSize = nbElapsed; | ||
409 : | |||
410 : | return S_OK; | ||
411 : | } | ||
412 : | |||
413 : | Isibaar | 2045 | STDMETHODIMP |
414 : | CIRecProgressNotify::GetMeasuredTimes (LONGLONG &outStopTimeMin, LONGLONG &outStopTimeMax, LONGLONG &outStartTimeMin, LONGLONG &outStartTimeMax) | ||
415 : | { | ||
416 : | outStopTimeMin = m_StopTimeMin; | ||
417 : | outStopTimeMax = m_StopTimeMax; | ||
418 : | outStartTimeMin = m_StartTimeMin; | ||
419 : | outStartTimeMax = m_StartTimeMax; | ||
420 : | return S_OK; | ||
421 : | } | ||
422 : | |||
423 : | STDMETHODIMP | ||
424 : | CIRecProgressNotify::SetForceTimeParams (LONGLONG inStartTimeOffset, LONGLONG inFpsNom, LONGLONG inFpsDen) | ||
425 : | { | ||
426 : | m_StartTimeMin = inStartTimeOffset; | ||
427 : | m_FpsNom = inFpsNom; | ||
428 : | m_FpsDen = inFpsDen; | ||
429 : | m_bForceTimeStamps = 1; | ||
430 : | return S_OK; | ||
431 : | } | ||
432 : | |||
433 : | STDMETHODIMP | ||
434 : | CIRecProgressNotify::SetAudioBitrate (int Bitrate) | ||
435 : | { | ||
436 : | m_AudioBitrate = Bitrate; | ||
437 : | return S_OK; | ||
438 : | } | ||
439 : | |||
440 : | Irhall | 2014 | CIRecProgressNotify::CIRecProgressNotify() |
441 : | { | ||
442 : | m_Pass = -1; | ||
443 : | m_MessageWnd = 0; | ||
444 : | m_TotalFrames = 0; | ||
445 : | m_SampleCnt = 0; | ||
446 : | m_TotalDataSize = 0; | ||
447 : | m_totalSize = 0; | ||
448 : | m_curSize = 0; | ||
449 : | m_elapsedSize = 0; | ||
450 : | Isibaar | 2045 | m_StopTimeMin = m_StopTimeMax = m_StartTimeMin = m_StartTimeMax = 0; |
451 : | m_bForceTimeStamps = 0; | ||
452 : | m_AudioBitrate = 1600; | ||
453 : | Irhall | 2014 | } |
454 : | |||
455 : | ////////////////////////////////////////////////////////////////// | ||
456 : | |||
457 : | CUnknown * WINAPI | ||
458 : | ChangeSubtypeT::CreateInstance(IUnknown *pUnk, HRESULT *phr) | ||
459 : | { | ||
460 : | CUnknown *pNewFilter = new ChangeSubtypeT(pUnk, phr ); | ||
461 : | |||
462 : | if (phr) { | ||
463 : | if (pNewFilter == NULL) *phr = E_OUTOFMEMORY; | ||
464 : | else *phr = S_OK; | ||
465 : | } | ||
466 : | |||
467 : | return pNewFilter; | ||
468 : | } | ||
469 : | |||
470 : | ChangeSubtypeT::ChangeSubtypeT(LPUNKNOWN pUnk, HRESULT *phr) : | ||
471 : | CTransformFilter("ChangeSubtypeT", pUnk, CLSID_ChangeSubtypeT) | ||
472 : | { | ||
473 : | m_OutFcc = 'DIVX'; // == FCC('xvid') | ||
474 : | m_SubtypeID = FOURCCMap('divx'); // FCC('XVID') | ||
475 : | m_SampleCnt = 0; | ||
476 : | |||
477 : | if (*phr) *phr = S_OK; | ||
478 : | |||
479 : | m_pMpeg4Sequence = 0; | ||
480 : | m_Mpeg4SequenceSize = 0; | ||
481 : | } | ||
482 : | |||
483 : | ChangeSubtypeT::~ChangeSubtypeT(void) | ||
484 : | { | ||
485 : | } | ||
486 : | |||
487 : | HRESULT | ||
488 : | ChangeSubtypeT::NonDelegatingQueryInterface(REFIID riid, void ** ppv) | ||
489 : | { | ||
490 : | if (riid == IID_IRecProgressNotify) | ||
491 : | return GetInterface((IRecProgressNotify*)this, ppv); | ||
492 : | |||
493 : | return CBaseFilter::NonDelegatingQueryInterface (riid, ppv); | ||
494 : | } | ||
495 : | |||
496 : | HRESULT | ||
497 : | ChangeSubtypeT::CheckInputType(const CMediaType *pmt) | ||
498 : | { | ||
499 : | if (!pmt) | ||
500 : | return E_POINTER; | ||
501 : | |||
502 : | if (pmt->majortype != MEDIATYPE_Video) | ||
503 : | return S_FALSE; | ||
504 : | |||
505 : | return S_OK; | ||
506 : | } | ||
507 : | |||
508 : | HRESULT | ||
509 : | ChangeSubtypeT::CheckTransform (const CMediaType *pmtIn, const CMediaType *pmtOut) | ||
510 : | { | ||
511 : | if (!m_pInput->IsConnected()) | ||
512 : | return E_UNEXPECTED; | ||
513 : | |||
514 : | if (pmtIn->majortype != MEDIATYPE_Video) | ||
515 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
516 : | |||
517 : | BITMAPINFOHEADER *pBmp = 0; | ||
518 : | |||
519 : | if (pmtOut->majortype == MEDIATYPE_Video) { | ||
520 : | |||
521 : | if (m_SubtypeID != pmtOut->subtype) | ||
522 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
523 : | |||
524 : | if (!pmtOut->pbFormat) | ||
525 : | return S_OK; | ||
526 : | |||
527 : | if (pmtOut->formattype == FORMAT_VideoInfo || | ||
528 : | pmtOut->formattype == FORMAT_MPEGVideo) | ||
529 : | { | ||
530 : | pBmp = &((VIDEOINFOHEADER *)pmtOut->pbFormat)->bmiHeader; | ||
531 : | } | ||
532 : | else if (pmtOut->formattype == FORMAT_VideoInfo2 || | ||
533 : | pmtOut->formattype == FORMAT_MPEG2Video) | ||
534 : | { | ||
535 : | pBmp = &((VIDEOINFOHEADER2 *)pmtOut->pbFormat)->bmiHeader; | ||
536 : | } | ||
537 : | else | ||
538 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
539 : | |||
540 : | if (m_OutFcc == pBmp->biCompression) | ||
541 : | return S_OK; | ||
542 : | } | ||
543 : | |||
544 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
545 : | } | ||
546 : | |||
547 : | HRESULT | ||
548 : | ChangeSubtypeT::DecideBufferSize(IMemAllocator * pAlloc, | ||
549 : | ALLOCATOR_PROPERTIES * ppropInputRequest) | ||
550 : | { | ||
551 : | if (!m_pInput->IsConnected()) | ||
552 : | return E_UNEXPECTED; | ||
553 : | |||
554 : | HRESULT hr = NOERROR; | ||
555 : | BITMAPINFOHEADER *pBmp = 0; | ||
556 : | |||
557 : | if (!m_OutMediaType.pbFormat) | ||
558 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
559 : | |||
560 : | if (m_OutMediaType.formattype == FORMAT_VideoInfo || | ||
561 : | m_OutMediaType.formattype == FORMAT_MPEGVideo) | ||
562 : | { | ||
563 : | pBmp = &((VIDEOINFOHEADER *)m_OutMediaType.pbFormat)->bmiHeader; | ||
564 : | } | ||
565 : | else if (m_OutMediaType.formattype == FORMAT_VideoInfo2 || | ||
566 : | m_OutMediaType.formattype == FORMAT_MPEG2Video) | ||
567 : | { | ||
568 : | pBmp = &((VIDEOINFOHEADER2 *)m_OutMediaType.pbFormat)->bmiHeader; | ||
569 : | } | ||
570 : | else | ||
571 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
572 : | |||
573 : | ppropInputRequest->cBuffers = 1; | ||
574 : | ppropInputRequest->cbBuffer = pBmp->biHeight*pBmp->biWidth * (pBmp->biBitCount+7)/8; | ||
575 : | |||
576 : | ALLOCATOR_PROPERTIES Actual; | ||
577 : | hr = pAlloc->SetProperties(ppropInputRequest,&Actual); | ||
578 : | if (FAILED(hr)) | ||
579 : | return hr; | ||
580 : | |||
581 : | if (ppropInputRequest->cBuffers > Actual.cBuffers || | ||
582 : | ppropInputRequest->cbBuffer > Actual.cbBuffer) | ||
583 : | return E_FAIL; | ||
584 : | |||
585 : | return S_OK; | ||
586 : | } | ||
587 : | |||
588 : | HRESULT | ||
589 : | ChangeSubtypeT::GetMediaType(int iPosition, CMediaType *pMediaType) | ||
590 : | { | ||
591 : | if (!m_pInput->IsConnected()) { | ||
592 : | return E_UNEXPECTED; | ||
593 : | } | ||
594 : | else if (iPosition < 0) { | ||
595 : | return E_INVALIDARG; | ||
596 : | } | ||
597 : | else if (iPosition > 0) { | ||
598 : | return VFW_S_NO_MORE_ITEMS; | ||
599 : | } | ||
600 : | else { //if (iPosition == 0) | ||
601 : | *pMediaType = m_OutMediaType; | ||
602 : | return S_OK; | ||
603 : | } | ||
604 : | } | ||
605 : | |||
606 : | HRESULT | ||
607 : | ChangeSubtypeT::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) | ||
608 : | { | ||
609 : | CMediaType mt; | ||
610 : | BITMAPINFOHEADER *pBmp = 0; | ||
611 : | pReceivePin->ConnectionMediaType(&mt); | ||
612 : | |||
613 : | if (mt.majortype == MEDIATYPE_Video) { | ||
614 : | if (direction == PINDIR_INPUT) { | ||
615 : | |||
616 : | // if (m_pOutput->IsConnected()) { | ||
617 : | // m_pInput->BreakConnection(); | ||
618 : | // } | ||
619 : | |||
620 : | m_InMediaType = mt; | ||
621 : | m_OutMediaType = mt; | ||
622 : | m_OutMediaType.subtype = m_SubtypeID; | ||
623 : | |||
624 : | int NewSequenceSize = 0; | ||
625 : | |||
626 : | if (m_InMediaType.formattype == FORMAT_VideoInfo || | ||
627 : | m_InMediaType.formattype == FORMAT_MPEGVideo) | ||
628 : | { | ||
629 : | pBmp = &((VIDEOINFOHEADER *)m_InMediaType.pbFormat)->bmiHeader; | ||
630 : | m_AvgTimeForFrame = (DWORD) ((VIDEOINFOHEADER *)m_InMediaType.pbFormat)->AvgTimePerFrame; | ||
631 : | } | ||
632 : | else { | ||
633 : | if (m_OutMediaType.formattype == FORMAT_VideoInfo2 || | ||
634 : | m_OutMediaType.formattype == FORMAT_MPEG2Video) | ||
635 : | { | ||
636 : | pBmp = &((VIDEOINFOHEADER2 *)m_InMediaType.pbFormat)->bmiHeader; | ||
637 : | m_AvgTimeForFrame = (DWORD) ((VIDEOINFOHEADER2 *)m_InMediaType.pbFormat)->AvgTimePerFrame; | ||
638 : | } | ||
639 : | else | ||
640 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
641 : | } | ||
642 : | |||
643 : | if (*m_InMediaType.FormatType() == FORMAT_MPEG2Video) { | ||
644 : | MPEG2VIDEOINFO *mpeg2info=(MPEG2VIDEOINFO*)m_InMediaType.Format(); | ||
645 : | |||
646 : | if (mpeg2info->hdr.bmiHeader.biCompression!=0 && mpeg2info->cbSequenceHeader>0) { | ||
647 : | |||
648 : | if (m_pMpeg4Sequence) | ||
649 : | free(m_pMpeg4Sequence); | ||
650 : | |||
651 : | m_Mpeg4SequenceSize = mpeg2info->cbSequenceHeader; | ||
652 : | |||
653 : | if (m_Mpeg4SequenceSize > 0) { | ||
654 : | m_pMpeg4Sequence = (BYTE *)malloc(m_Mpeg4SequenceSize*sizeof(BYTE)); | ||
655 : | memcpy(m_pMpeg4Sequence, (const BYTE *)mpeg2info->dwSequenceHeader, m_Mpeg4SequenceSize); | ||
656 : | } | ||
657 : | } | ||
658 : | } | ||
659 : | |||
660 : | VIDEOINFOHEADER * pVih = (VIDEOINFOHEADER*)m_OutMediaType.ReallocFormatBuffer(sizeof(VIDEOINFOHEADER)); | ||
661 : | if (pVih==NULL) { | ||
662 : | return E_OUTOFMEMORY; | ||
663 : | } | ||
664 : | |||
665 : | ZeroMemory(pVih, sizeof (VIDEOINFOHEADER)); | ||
666 : | CopyMemory(&pVih->bmiHeader, pBmp, sizeof(BITMAPINFOHEADER)); | ||
667 : | |||
668 : | /* set output format */ | ||
669 : | m_OutMediaType.SetType(&MEDIATYPE_Video); | ||
670 : | m_OutMediaType.SetFormatType(&FORMAT_VideoInfo); | ||
671 : | |||
672 : | m_OutMediaType.SetSubtype(&m_SubtypeID); | ||
673 : | pVih->bmiHeader.biCompression = m_OutFcc; | ||
674 : | |||
675 : | pVih->AvgTimePerFrame = m_AvgTimeForFrame; | ||
676 : | pVih->dwBitErrorRate = 0; | ||
677 : | pVih->dwBitRate = 8 * (DWORD)(((float)pVih->bmiHeader.biSizeImage * 10000000) / m_AvgTimeForFrame); | ||
678 : | |||
679 : | m_OutMediaType.SetTemporalCompression(TRUE); | ||
680 : | m_OutMediaType.SetVariableSize(); | ||
681 : | |||
682 : | if (m_AvgTimeForFrame) { | ||
683 : | switch (m_AvgTimeForFrame) { | ||
684 : | |||
685 : | case 416666: // 24.0 FPS | ||
686 : | m_FpsNom = 24; | ||
687 : | m_FpsDen = 1; | ||
688 : | break; | ||
689 : | |||
690 : | case 417083: // 23.97 FPS | ||
691 : | m_FpsNom = 24000; | ||
692 : | m_FpsDen = 1001; | ||
693 : | break; | ||
694 : | |||
695 : | case 333333: // 30.0 FPS | ||
696 : | m_FpsNom = 30; | ||
697 : | m_FpsDen = 1; | ||
698 : | break; | ||
699 : | |||
700 : | case 333666: // 29.97 FPS | ||
701 : | m_FpsNom = 30000; | ||
702 : | m_FpsDen = 1001; | ||
703 : | break; | ||
704 : | |||
705 : | default: | ||
706 : | m_FpsNom = (int) (10000000 / m_AvgTimeForFrame); | ||
707 : | m_FpsDen = 1; | ||
708 : | } | ||
709 : | } | ||
710 : | |||
711 : | m_SampleCnt = 0; | ||
712 : | Isibaar | 2045 | m_UnitDuration = (10000000LL * m_FpsDen)/m_FpsNom; |
713 : | m_UnitTimeDelta = m_UnitDuration / 5; | ||
714 : | if (m_UnitTimeDelta < 1000) m_UnitTimeDelta = m_UnitDuration > 2000 ? 1000 : m_UnitDuration/2; | ||
715 : | m_stopTime = m_startTime = 0; | ||
716 : | |||
717 : | |||
718 : | m_MaxStartTime = m_MaxStopTime = 0; | ||
719 : | |||
720 : | Irhall | 2014 | return S_OK; |
721 : | } | ||
722 : | else { // if (direction == PINDIR_OUTPUT) { | ||
723 : | if (!m_pInput->IsConnected()) | ||
724 : | return E_UNEXPECTED; | ||
725 : | |||
726 : | if (m_SubtypeID != mt.subtype) | ||
727 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
728 : | |||
729 : | if (!mt.pbFormat) | ||
730 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
731 : | |||
732 : | if (mt.formattype == FORMAT_VideoInfo || | ||
733 : | mt.formattype == FORMAT_MPEGVideo) | ||
734 : | { | ||
735 : | pBmp = &((VIDEOINFOHEADER *)mt.pbFormat)->bmiHeader; | ||
736 : | } | ||
737 : | else if (mt.formattype == FORMAT_VideoInfo2 || | ||
738 : | mt.formattype == FORMAT_MPEG2Video) | ||
739 : | { | ||
740 : | pBmp = &((VIDEOINFOHEADER2 *)mt.pbFormat)->bmiHeader; | ||
741 : | } | ||
742 : | else | ||
743 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
744 : | |||
745 : | Isibaar | 2045 | if (m_bForceTimeStamps) { |
746 : | if (m_OutMediaType.formattype == FORMAT_VideoInfo || | ||
747 : | m_OutMediaType.formattype == FORMAT_MPEGVideo) { | ||
748 : | ((VIDEOINFOHEADER *)m_OutMediaType.pbFormat)->AvgTimePerFrame = | ||
749 : | m_AvgTimeForFrame = (DWORD) (m_FpsNom/m_FpsDen); | ||
750 : | } else if (m_OutMediaType.formattype == FORMAT_VideoInfo2 || | ||
751 : | m_OutMediaType.formattype == FORMAT_MPEG2Video) { | ||
752 : | ((VIDEOINFOHEADER2 *)m_OutMediaType.pbFormat)->AvgTimePerFrame = | ||
753 : | m_AvgTimeForFrame = (DWORD) (m_FpsNom/m_FpsDen); | ||
754 : | } | ||
755 : | } | ||
756 : | |||
757 : | Irhall | 2014 | if (m_OutFcc == pBmp->biCompression) |
758 : | return S_OK; | ||
759 : | } | ||
760 : | } | ||
761 : | |||
762 : | return VFW_E_TYPE_NOT_ACCEPTED; | ||
763 : | } | ||
764 : | |||
765 : | HRESULT | ||
766 : | ChangeSubtypeT::Transform(IMediaSample *pIn, IMediaSample *pOut) | ||
767 : | { | ||
768 : | BITMAPINFOHEADER *pBmpIn=0, *pBmpOut=0; | ||
769 : | HRESULT hr = S_FALSE; | ||
770 : | |||
771 : | if (m_InMediaType.formattype == FORMAT_VideoInfo || | ||
772 : | m_InMediaType.formattype == FORMAT_MPEGVideo) | ||
773 : | { | ||
774 : | pBmpIn = &((VIDEOINFOHEADER *)m_InMediaType.pbFormat)->bmiHeader; | ||
775 : | } | ||
776 : | else if (m_InMediaType.formattype == FORMAT_VideoInfo2 || | ||
777 : | m_InMediaType.formattype == FORMAT_MPEG2Video) | ||
778 : | { | ||
779 : | pBmpIn = &((VIDEOINFOHEADER2 *)m_InMediaType.pbFormat)->bmiHeader; | ||
780 : | } | ||
781 : | |||
782 : | if (m_OutMediaType.formattype == FORMAT_VideoInfo || | ||
783 : | m_OutMediaType.formattype == FORMAT_MPEGVideo) | ||
784 : | { | ||
785 : | pBmpOut = &((VIDEOINFOHEADER *)m_OutMediaType.pbFormat)->bmiHeader; | ||
786 : | } | ||
787 : | else if (m_OutMediaType.formattype == FORMAT_VideoInfo2 || | ||
788 : | m_OutMediaType.formattype == FORMAT_MPEG2Video) | ||
789 : | { | ||
790 : | pBmpOut = &((VIDEOINFOHEADER2 *)m_OutMediaType.pbFormat)->bmiHeader; | ||
791 : | } | ||
792 : | |||
793 : | if (pBmpIn && pBmpOut && m_InMediaType.lSampleSize == m_OutMediaType.lSampleSize) | ||
794 : | { | ||
795 : | BYTE *pBufIn, *pBufOut; | ||
796 : | pIn->GetPointer(&pBufIn); | ||
797 : | pOut->GetPointer(&pBufOut); | ||
798 : | DWORD lSize = pIn->GetActualDataLength(); | ||
799 : | |||
800 : | DWORD OutOffset = 0; | ||
801 : | if (*((int *)pBufIn) != 0xB0010000 && m_pMpeg4Sequence) { | ||
802 : | Isibaar | 2045 | int FrameType = -1; |
803 : | for (int iOffset=0; iOffset < (int) (lSize - 5) && FrameType == -1; iOffset++) { | ||
804 : | if (*((int *)(&(pBufIn[iOffset]))) == 0xB6010000) { | ||
805 : | FrameType = (pBufIn[iOffset + 4] >> 6)& 3; | ||
806 : | } | ||
807 : | } | ||
808 : | pOut->SetSyncPoint(FrameType == 0 ? TRUE : FALSE); | ||
809 : | //if (pIn->IsSyncPoint() == S_OK) { // I-VOP // IsSyncPoint() is not reliable !! | ||
810 : | if (FrameType == 0) { | ||
811 : | Irhall | 2014 | memcpy(pBufOut, m_pMpeg4Sequence, m_Mpeg4SequenceSize); |
812 : | OutOffset = m_Mpeg4SequenceSize; | ||
813 : | } | ||
814 : | } | ||
815 : | |||
816 : | pOut->SetActualDataLength(lSize + OutOffset); | ||
817 : | memcpy(&pBufOut[OutOffset], pBufIn, lSize); | ||
818 : | Isibaar | 2045 | LONGLONG ExpectedStart = m_stopTime; |
819 : | LONGLONG ExpectedStop = m_stopTime + m_UnitDuration; | ||
820 : | Irhall | 2014 | |
821 : | LONGLONG sTime, eTime; | ||
822 : | pOut->GetTime(&sTime, &eTime); | ||
823 : | int bSetTime = 0; | ||
824 : | LONGLONG sDuration = eTime - sTime; | ||
825 : | |||
826 : | Isibaar | 2045 | if (m_Pass == 1) { |
827 : | if (m_SampleCnt == 0) { | ||
828 : | m_StopTimeMin = m_StopTimeMax = eTime; | ||
829 : | m_StartTimeMin = m_StartTimeMax = sTime; | ||
830 : | } else { | ||
831 : | if (m_StopTimeMin > eTime) m_StopTimeMin = eTime; | ||
832 : | if (m_StopTimeMax < eTime) m_StopTimeMax = eTime; | ||
833 : | if (m_StartTimeMin > sTime) m_StartTimeMin = sTime; | ||
834 : | if (m_StartTimeMax < sTime) m_StartTimeMax = sTime; | ||
835 : | } | ||
836 : | } else if (m_SampleCnt == 0 && m_bForceTimeStamps) { | ||
837 : | m_UnitDuration = m_FpsNom/m_FpsDen; | ||
838 : | m_UnitTimeDelta = m_UnitDuration / 5; | ||
839 : | if (m_UnitTimeDelta < 1000) m_UnitTimeDelta = m_UnitDuration > 2000 ? 1000 : m_UnitDuration/2; | ||
840 : | } | ||
841 : | |||
842 : | int bForceStopTime = 0; | ||
843 : | if (abs((long)((LONGLONG)(ExpectedStop - m_MaxStopTime))) < m_UnitTimeDelta) { | ||
844 : | // re-use of time that had one of previous samples | ||
845 : | // in case when times of samples are reordered | ||
846 : | // to keep exactly in sync with speed of playing of original speed | ||
847 : | // in long distance. Any way of calculation based on | ||
848 : | // number of samples may fail if stream is long enough | ||
849 : | // and frame duration is calculated not with | ||
850 : | // absolute precision (NTSC - family framerates: 23.98, 29.97, etc...) | ||
851 : | |||
852 : | ExpectedStop = m_MaxStopTime; | ||
853 : | bForceStopTime = 1; | ||
854 : | if (ExpectedStart + m_UnitDuration > ExpectedStop + m_UnitTimeDelta) { | ||
855 : | ExpectedStart = m_MaxStartTime; | ||
856 : | if (ExpectedStart + m_UnitDuration > ExpectedStop) | ||
857 : | ExpectedStart = ExpectedStop - m_UnitDuration; | ||
858 : | } | ||
859 : | } | ||
860 : | |||
861 : | //LONGLONG eTimeN = eTime * m_FpsNom, Den0 = 10000000LL * m_FpsDen; | ||
862 : | //int SampleEMin = ((eTimeN < 100000) ? 0 : eTimeN - 10000)/Den0, SampleEMax = (eTimeN + 10000)/Den0; | ||
863 : | //int TimeEDiff = eTime - m_stopTime; | ||
864 : | LONGLONG MaxStartTime = max(m_MaxStartTime, sTime), | ||
865 : | MaxStopTime = max(m_MaxStopTime, eTime); | ||
866 : | |||
867 : | Irhall | 2014 | // simply set correct end time - seems to work here... |
868 : | Isibaar | 2045 | |
869 : | //if (m_Pass ==2 && m_bForceTimeStamps) { | ||
870 : | // sTime = m_SampleCnt * m_FpsNom / m_FpsDen; | ||
871 : | // eTime = (m_SampleCnt +1) * m_FpsNom / m_FpsDen; | ||
872 : | // bSetTime = 1; | ||
873 : | //} | ||
874 : | |||
875 : | if (eTime + m_UnitTimeDelta < sTime + m_UnitDuration) { | ||
876 : | eTime = sTime + m_UnitDuration; | ||
877 : | Irhall | 2014 | bSetTime = 1; |
878 : | Isibaar | 2045 | } |
879 : | Irhall | 2014 | |
880 : | Isibaar | 2045 | if ((bForceStopTime) || (eTime + m_UnitDuration < ExpectedStop)) { |
881 : | //if ((bForceStopTime) || (eTime > ExpectedStop + m_UnitTimeDelta) || (eTime + m_UnitTimeDelta < ExpectedStop)) { | ||
882 : | eTime = ExpectedStop; | ||
883 : | sTime = ExpectedStart; | ||
884 : | bSetTime = 1; | ||
885 : | } | ||
886 : | m_MaxStartTime = max(MaxStartTime, sTime); | ||
887 : | m_MaxStopTime = max(MaxStopTime, eTime); | ||
888 : | |||
889 : | Irhall | 2014 | if (bSetTime) pOut->SetTime(&sTime, &eTime); |
890 : | |||
891 : | m_startTime = sTime; | ||
892 : | m_stopTime = eTime; | ||
893 : | m_SampleCnt ++; | ||
894 : | |||
895 : | int CurPos = (int) ((double)(100.0 * m_SampleCnt/m_TotalFrames) + 0.5); | ||
896 : | if (m_Pass == 0) | ||
897 : | CurPos /= 2; | ||
898 : | else if (m_Pass == 2) | ||
899 : | CurPos = CurPos /2 + 50; | ||
900 : | |||
901 : | if (m_MessageWnd) | ||
902 : | PostMessage(m_MessageWnd, PBM_SETPOS, CurPos, 0); | ||
903 : | |||
904 : | hr = S_OK; | ||
905 : | } | ||
906 : | |||
907 : | return hr; | ||
908 : | } |
No admin address has been configured | ViewVC Help |
Powered by ViewVC 1.0.4 |