/***************************************************************************** * * Xvid MiniConvert * - Helper filters - * * Copyright(C) 2011 Xvid Solutions GmbH * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation ; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY ; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ * ****************************************************************************/ /* * Author(s): Ireneusz Hallmann * ****************************************************************************/ #include "stdafx.h" #include "filters.h" #include "mmreg.h" // WAVE_FORMAT_MPEGLAYER3 format structure ////////////////////////////////////////////////////////////////////////////////////////////////// CUnknown * WINAPI CProgressNotifyFilter::CreateInstance(IUnknown *pUnk, HRESULT *phr, int Type) { CUnknown *pNewFilter = new CProgressNotifyFilter(pUnk, phr, Type); if (phr) { if (pNewFilter == NULL) *phr = E_OUTOFMEMORY; else *phr = S_OK; } return pNewFilter; } CProgressNotifyFilter::CProgressNotifyFilter(LPUNKNOWN pUnk, HRESULT *phr, int Type) : CTransInPlaceFilter("ProgressNotify", pUnk, CLSID_ProgressNotifyFilter, phr, false) { m_MessageWnd = 0; m_SampleCnt = 0; m_Pass = 1; m_Type = Type; m_startTime = 0; m_stopTime = 0; m_Width = 0, m_Height = 0; m_AvgTimeForFrame = 0; if (*phr) *phr = S_OK; } CProgressNotifyFilter::~CProgressNotifyFilter(void) { } HRESULT CProgressNotifyFilter::NonDelegatingQueryInterface(REFIID riid, void ** ppv) { if (riid == IID_IRecProgressNotify) return GetInterface((IRecProgressNotify*)this, ppv); return CBaseFilter::NonDelegatingQueryInterface (riid, ppv); } HRESULT CProgressNotifyFilter::CheckInputType(const CMediaType *mtIn) { if (mtIn->majortype != MEDIATYPE_Video && mtIn->majortype != MEDIATYPE_Audio) { return VFW_E_TYPE_NOT_ACCEPTED; } if (mtIn->formattype != FORMAT_None) { if (mtIn->formattype == FORMAT_VideoInfo || mtIn->formattype == FORMAT_MPEGVideo) { m_AvgTimeForFrame = ((VIDEOINFOHEADER *)mtIn->pbFormat)->AvgTimePerFrame; m_Width = ((VIDEOINFOHEADER *)mtIn->pbFormat)->bmiHeader.biWidth; m_Height = ((VIDEOINFOHEADER *)mtIn->pbFormat)->bmiHeader.biHeight; } else if (mtIn->formattype == FORMAT_VideoInfo2 || mtIn->formattype == FORMAT_MPEG2Video) { m_AvgTimeForFrame = ((VIDEOINFOHEADER2 *)mtIn->pbFormat)->AvgTimePerFrame; m_Width = ((VIDEOINFOHEADER2 *)mtIn->pbFormat)->bmiHeader.biWidth; m_Height = ((VIDEOINFOHEADER2 *)mtIn->pbFormat)->bmiHeader.biHeight; } else if (mtIn->formattype == FORMAT_WaveFormatEx && m_Type == 2) { MPEGLAYER3WAVEFORMAT *pMp3 = (MPEGLAYER3WAVEFORMAT *)mtIn->pbFormat; if (pMp3->wfx.nAvgBytesPerSec != 16000) return VFW_E_TYPE_NOT_ACCEPTED; // WAVEFORMATEX *pWaveFormat = (WAVEFORMATEX *)mtIn->pbFormat; // if (pWaveFormat->nChannels > 2) // return VFW_E_TYPE_NOT_ACCEPTED; } else if (m_Type == 0) { return VFW_E_TYPE_NOT_ACCEPTED; } } return S_OK; } HRESULT CProgressNotifyFilter::Transform(IMediaSample *pSample) { LONGLONG osTime, sTime, eTime; pSample->GetTime(&osTime, &eTime); sTime = osTime; int bSetTime = 0; if (m_Type == 0) { // Video #if 0 // emms instruction - for debug #ifdef __FUNCTION__ // Visual Studio __asm emms; #else __asm ("emms"); #endif #endif m_TotalDataSize += pSample->GetActualDataLength(); m_SampleCnt++; int CurPos = (int) (m_TotalFrames ? (((double)(100 * m_SampleCnt/m_TotalFrames) + 0.5)) : 0); if (m_Pass == 0) { CurPos /= 2; } else if (m_Pass == 2) { CurPos = CurPos/2 + 50; } if (m_totalSize > 0) { CurPos = ((CurPos*m_curSize) / m_totalSize); CurPos += ((100*m_elapsedSize) / m_totalSize); } if (m_MessageWnd) PostMessage(m_MessageWnd, PBM_SETPOS, CurPos, 0); } else { // Audio MPEGLAYER3WAVEFORMAT *pMp3 = 0; if (m_MediaType.subtype == MEDIASUBTYPE_MP3) { pMp3 = (MPEGLAYER3WAVEFORMAT *)m_MediaType.pbFormat; DWORD ThisSamples = (pMp3->wfx.nSamplesPerSec >= 32000 ? 576 : 1152) * pMp3->nFramesPerBlock; m_SampleCnt += ThisSamples; LONGLONG sDuration = eTime - sTime; if (((m_SampleCnt || sTime) && sTime <= m_stopTime)) { sTime = m_stopTime + 1; bSetTime = 1; } if (eTime <= sTime || sDuration != (ThisSamples * 10000000LL * m_FpsDen)/m_FpsNom) { sDuration = (ThisSamples * 10000000LL * m_FpsDen)/m_FpsNom - 1; eTime = sTime + sDuration; bSetTime = 1; } sTime = osTime; //!! pSample->SetSyncPoint(TRUE); } } if (bSetTime) pSample->SetTime(&sTime, &eTime); m_startTime = sTime; m_stopTime = eTime; return S_OK; } HRESULT CProgressNotifyFilter::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) { HRESULT hr = pReceivePin->ConnectionMediaType(&m_MediaType); m_MinSampleSize = 0; if (hr == S_OK) { if (m_MediaType.formattype == FORMAT_VideoInfo || m_MediaType.formattype == FORMAT_MPEGVideo) { m_AvgTimeForFrame = ((VIDEOINFOHEADER *)m_MediaType.pbFormat)->AvgTimePerFrame; if (direction == PINDIR_INPUT) { if (m_MediaType.bTemporalCompression || m_MediaType.lSampleSize <=1) { m_MinSampleSize = ((VIDEOINFOHEADER *)m_MediaType.pbFormat)->bmiHeader.biHeight * ((VIDEOINFOHEADER *)m_MediaType.pbFormat)->bmiHeader.biWidth * 4; } } } else if (m_MediaType.formattype == FORMAT_VideoInfo2 || m_MediaType.formattype == FORMAT_MPEG2Video) { m_AvgTimeForFrame = ((VIDEOINFOHEADER2 *)m_MediaType.pbFormat)->AvgTimePerFrame; if (direction == PINDIR_INPUT) { if (m_MediaType.bTemporalCompression || m_MediaType.lSampleSize <=1) { m_MinSampleSize = ((VIDEOINFOHEADER2 *)m_MediaType.pbFormat)->bmiHeader.biHeight * ((VIDEOINFOHEADER2 *)m_MediaType.pbFormat)->bmiHeader.biWidth * 4; } } } else if (m_Type == 0) { hr = VFW_E_TYPE_NOT_ACCEPTED; } if (m_AvgTimeForFrame) { switch (m_AvgTimeForFrame) { case 416666: // 24.0 FPS m_FpsNom = 24; m_FpsDen = 1; break; case 417083: // 23.97 FPS m_FpsNom = 24000; m_FpsDen = 1001; break; case 333333: // 30.0 FPS m_FpsNom = 30; m_FpsDen = 1; break; case 333666: // 29.97 FPS m_FpsNom = 30000; m_FpsDen = 1001; break; default: m_FpsNom = (int) (10000000 / m_AvgTimeForFrame); m_FpsDen = 1; } } else if (m_Type == 1 || m_Type == 2) { WAVEFORMATEX *pWave = (WAVEFORMATEX *)m_MediaType.pbFormat; m_FpsNom = pWave->nSamplesPerSec; m_FpsDen = 1; } } return hr; } HRESULT CProgressNotifyFilter::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties) { ALLOCATOR_PROPERTIES Request, Actual; HRESULT hr; // If we are connected upstream, get his views if (m_pInput->IsConnected()) { // Get the input pin allocator, and get its size and count. // we don't care about his alignment and prefix. hr = InputPin()->PeekAllocator()->GetProperties(&Request); if (FAILED(hr)) { // Input connected but with a secretive allocator - enough! return hr; } if (m_MinSampleSize && (m_Type == 0)) { if (Request.cbBuffer < m_MinSampleSize) { Request.cbBuffer = m_MinSampleSize; } } } else { // We're reduced to blind guessing. Let's guess one byte and if // this isn't enough then when the other pin does get connected // we can revise it. ZeroMemory(&Request, sizeof(Request)); Request.cBuffers = 1; Request.cbBuffer = 1; } #ifdef _DEBUG DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), Request.cBuffers, Request.cbBuffer)); #endif // Pass the allocator requirements to our output side // but do a little sanity checking first or we'll just hit // asserts in the allocator. pProperties->cBuffers = Request.cBuffers; pProperties->cbBuffer = Request.cbBuffer; pProperties->cbAlign = Request.cbAlign; if (pProperties->cBuffers<=0) { pProperties->cBuffers = 1; } if (pProperties->cbBuffer<=0) { pProperties->cbBuffer = 1; } hr = pAlloc->SetProperties(pProperties, &Actual); if (FAILED(hr)) { return hr; } #ifdef _DEBUG DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); #endif // Make sure we got the right alignment and at least the minimum required if ((Request.cBuffers > Actual.cBuffers) || (Request.cbBuffer > Actual.cbBuffer) || (Request.cbAlign > Actual.cbAlign)) { return E_FAIL; } return NOERROR; } ////////////////////////////////////////////////////////////////////////////////////////// HRESULT CIRecProgressNotify::GetDimensions(DWORD &Width, DWORD &Height) { Width = m_Width; Height = m_Height; return S_OK; } HRESULT CIRecProgressNotify::GetBitrate(DWORD &OutFramesCount, LONGLONG &OutTotalDataSize) { OutFramesCount = m_SampleCnt; OutTotalDataSize = m_TotalDataSize; return S_OK; } HRESULT CIRecProgressNotify::SetPass(int in_Pass) { m_Pass = in_Pass; m_SampleCnt = 0; return S_OK; } HRESULT CIRecProgressNotify::SetTotalFrames(DWORD in_TotalFrames) { m_TotalFrames = in_TotalFrames; return S_OK; } HRESULT CIRecProgressNotify::SetNotifyWnd(HWND in_hWnd) { m_MessageWnd = in_hWnd; return S_OK; } STDMETHODIMP CIRecProgressNotify::SetTotalSize(int nbTotal) { m_totalSize = nbTotal; return S_OK; } STDMETHODIMP CIRecProgressNotify::SetCurSize(int nbCur) { m_curSize = nbCur; return S_OK; } STDMETHODIMP CIRecProgressNotify::SetElapsedSize(int nbElapsed) { m_elapsedSize = nbElapsed; return S_OK; } CIRecProgressNotify::CIRecProgressNotify() { m_Pass = -1; m_MessageWnd = 0; m_TotalFrames = 0; m_SampleCnt = 0; m_TotalDataSize = 0; m_totalSize = 0; m_curSize = 0; m_elapsedSize = 0; } ////////////////////////////////////////////////////////////////// CUnknown * WINAPI ChangeSubtypeT::CreateInstance(IUnknown *pUnk, HRESULT *phr) { CUnknown *pNewFilter = new ChangeSubtypeT(pUnk, phr ); if (phr) { if (pNewFilter == NULL) *phr = E_OUTOFMEMORY; else *phr = S_OK; } return pNewFilter; } ChangeSubtypeT::ChangeSubtypeT(LPUNKNOWN pUnk, HRESULT *phr) : CTransformFilter("ChangeSubtypeT", pUnk, CLSID_ChangeSubtypeT) { m_OutFcc = 'DIVX'; // == FCC('xvid') m_SubtypeID = FOURCCMap('divx'); // FCC('XVID') m_SampleCnt = 0; if (*phr) *phr = S_OK; m_pMpeg4Sequence = 0; m_Mpeg4SequenceSize = 0; } ChangeSubtypeT::~ChangeSubtypeT(void) { } HRESULT ChangeSubtypeT::NonDelegatingQueryInterface(REFIID riid, void ** ppv) { if (riid == IID_IRecProgressNotify) return GetInterface((IRecProgressNotify*)this, ppv); return CBaseFilter::NonDelegatingQueryInterface (riid, ppv); } HRESULT ChangeSubtypeT::CheckInputType(const CMediaType *pmt) { if (!pmt) return E_POINTER; if (pmt->majortype != MEDIATYPE_Video) return S_FALSE; return S_OK; } HRESULT ChangeSubtypeT::CheckTransform (const CMediaType *pmtIn, const CMediaType *pmtOut) { if (!m_pInput->IsConnected()) return E_UNEXPECTED; if (pmtIn->majortype != MEDIATYPE_Video) return VFW_E_TYPE_NOT_ACCEPTED; BITMAPINFOHEADER *pBmp = 0; if (pmtOut->majortype == MEDIATYPE_Video) { if (m_SubtypeID != pmtOut->subtype) return VFW_E_TYPE_NOT_ACCEPTED; if (!pmtOut->pbFormat) return S_OK; if (pmtOut->formattype == FORMAT_VideoInfo || pmtOut->formattype == FORMAT_MPEGVideo) { pBmp = &((VIDEOINFOHEADER *)pmtOut->pbFormat)->bmiHeader; } else if (pmtOut->formattype == FORMAT_VideoInfo2 || pmtOut->formattype == FORMAT_MPEG2Video) { pBmp = &((VIDEOINFOHEADER2 *)pmtOut->pbFormat)->bmiHeader; } else return VFW_E_TYPE_NOT_ACCEPTED; if (m_OutFcc == pBmp->biCompression) return S_OK; } return VFW_E_TYPE_NOT_ACCEPTED; } HRESULT ChangeSubtypeT::DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * ppropInputRequest) { if (!m_pInput->IsConnected()) return E_UNEXPECTED; HRESULT hr = NOERROR; BITMAPINFOHEADER *pBmp = 0; if (!m_OutMediaType.pbFormat) return VFW_E_TYPE_NOT_ACCEPTED; if (m_OutMediaType.formattype == FORMAT_VideoInfo || m_OutMediaType.formattype == FORMAT_MPEGVideo) { pBmp = &((VIDEOINFOHEADER *)m_OutMediaType.pbFormat)->bmiHeader; } else if (m_OutMediaType.formattype == FORMAT_VideoInfo2 || m_OutMediaType.formattype == FORMAT_MPEG2Video) { pBmp = &((VIDEOINFOHEADER2 *)m_OutMediaType.pbFormat)->bmiHeader; } else return VFW_E_TYPE_NOT_ACCEPTED; ppropInputRequest->cBuffers = 1; ppropInputRequest->cbBuffer = pBmp->biHeight*pBmp->biWidth * (pBmp->biBitCount+7)/8; ALLOCATOR_PROPERTIES Actual; hr = pAlloc->SetProperties(ppropInputRequest,&Actual); if (FAILED(hr)) return hr; if (ppropInputRequest->cBuffers > Actual.cBuffers || ppropInputRequest->cbBuffer > Actual.cbBuffer) return E_FAIL; return S_OK; } HRESULT ChangeSubtypeT::GetMediaType(int iPosition, CMediaType *pMediaType) { if (!m_pInput->IsConnected()) { return E_UNEXPECTED; } else if (iPosition < 0) { return E_INVALIDARG; } else if (iPosition > 0) { return VFW_S_NO_MORE_ITEMS; } else { //if (iPosition == 0) *pMediaType = m_OutMediaType; return S_OK; } } HRESULT ChangeSubtypeT::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) { CMediaType mt; BITMAPINFOHEADER *pBmp = 0; pReceivePin->ConnectionMediaType(&mt); if (mt.majortype == MEDIATYPE_Video) { if (direction == PINDIR_INPUT) { // if (m_pOutput->IsConnected()) { // m_pInput->BreakConnection(); // } m_InMediaType = mt; m_OutMediaType = mt; m_OutMediaType.subtype = m_SubtypeID; int NewSequenceSize = 0; if (m_InMediaType.formattype == FORMAT_VideoInfo || m_InMediaType.formattype == FORMAT_MPEGVideo) { pBmp = &((VIDEOINFOHEADER *)m_InMediaType.pbFormat)->bmiHeader; m_AvgTimeForFrame = (DWORD) ((VIDEOINFOHEADER *)m_InMediaType.pbFormat)->AvgTimePerFrame; } else { if (m_OutMediaType.formattype == FORMAT_VideoInfo2 || m_OutMediaType.formattype == FORMAT_MPEG2Video) { pBmp = &((VIDEOINFOHEADER2 *)m_InMediaType.pbFormat)->bmiHeader; m_AvgTimeForFrame = (DWORD) ((VIDEOINFOHEADER2 *)m_InMediaType.pbFormat)->AvgTimePerFrame; } else return VFW_E_TYPE_NOT_ACCEPTED; } if (*m_InMediaType.FormatType() == FORMAT_MPEG2Video) { MPEG2VIDEOINFO *mpeg2info=(MPEG2VIDEOINFO*)m_InMediaType.Format(); if (mpeg2info->hdr.bmiHeader.biCompression!=0 && mpeg2info->cbSequenceHeader>0) { if (m_pMpeg4Sequence) free(m_pMpeg4Sequence); m_Mpeg4SequenceSize = mpeg2info->cbSequenceHeader; if (m_Mpeg4SequenceSize > 0) { m_pMpeg4Sequence = (BYTE *)malloc(m_Mpeg4SequenceSize*sizeof(BYTE)); memcpy(m_pMpeg4Sequence, (const BYTE *)mpeg2info->dwSequenceHeader, m_Mpeg4SequenceSize); } } } VIDEOINFOHEADER * pVih = (VIDEOINFOHEADER*)m_OutMediaType.ReallocFormatBuffer(sizeof(VIDEOINFOHEADER)); if (pVih==NULL) { return E_OUTOFMEMORY; } ZeroMemory(pVih, sizeof (VIDEOINFOHEADER)); CopyMemory(&pVih->bmiHeader, pBmp, sizeof(BITMAPINFOHEADER)); /* set output format */ m_OutMediaType.SetType(&MEDIATYPE_Video); m_OutMediaType.SetFormatType(&FORMAT_VideoInfo); m_OutMediaType.SetSubtype(&m_SubtypeID); pVih->bmiHeader.biCompression = m_OutFcc; pVih->AvgTimePerFrame = m_AvgTimeForFrame; pVih->dwBitErrorRate = 0; pVih->dwBitRate = 8 * (DWORD)(((float)pVih->bmiHeader.biSizeImage * 10000000) / m_AvgTimeForFrame); m_OutMediaType.SetTemporalCompression(TRUE); m_OutMediaType.SetVariableSize(); if (m_AvgTimeForFrame) { switch (m_AvgTimeForFrame) { case 416666: // 24.0 FPS m_FpsNom = 24; m_FpsDen = 1; break; case 417083: // 23.97 FPS m_FpsNom = 24000; m_FpsDen = 1001; break; case 333333: // 30.0 FPS m_FpsNom = 30; m_FpsDen = 1; break; case 333666: // 29.97 FPS m_FpsNom = 30000; m_FpsDen = 1001; break; default: m_FpsNom = (int) (10000000 / m_AvgTimeForFrame); m_FpsDen = 1; } } m_SampleCnt = 0; return S_OK; } else { // if (direction == PINDIR_OUTPUT) { if (!m_pInput->IsConnected()) return E_UNEXPECTED; if (m_SubtypeID != mt.subtype) return VFW_E_TYPE_NOT_ACCEPTED; if (!mt.pbFormat) return VFW_E_TYPE_NOT_ACCEPTED; if (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_MPEGVideo) { pBmp = &((VIDEOINFOHEADER *)mt.pbFormat)->bmiHeader; } else if (mt.formattype == FORMAT_VideoInfo2 || mt.formattype == FORMAT_MPEG2Video) { pBmp = &((VIDEOINFOHEADER2 *)mt.pbFormat)->bmiHeader; } else return VFW_E_TYPE_NOT_ACCEPTED; if (m_OutFcc == pBmp->biCompression) return S_OK; } } return VFW_E_TYPE_NOT_ACCEPTED; } HRESULT ChangeSubtypeT::Transform(IMediaSample *pIn, IMediaSample *pOut) { BITMAPINFOHEADER *pBmpIn=0, *pBmpOut=0; HRESULT hr = S_FALSE; if (m_InMediaType.formattype == FORMAT_VideoInfo || m_InMediaType.formattype == FORMAT_MPEGVideo) { pBmpIn = &((VIDEOINFOHEADER *)m_InMediaType.pbFormat)->bmiHeader; } else if (m_InMediaType.formattype == FORMAT_VideoInfo2 || m_InMediaType.formattype == FORMAT_MPEG2Video) { pBmpIn = &((VIDEOINFOHEADER2 *)m_InMediaType.pbFormat)->bmiHeader; } if (m_OutMediaType.formattype == FORMAT_VideoInfo || m_OutMediaType.formattype == FORMAT_MPEGVideo) { pBmpOut = &((VIDEOINFOHEADER *)m_OutMediaType.pbFormat)->bmiHeader; } else if (m_OutMediaType.formattype == FORMAT_VideoInfo2 || m_OutMediaType.formattype == FORMAT_MPEG2Video) { pBmpOut = &((VIDEOINFOHEADER2 *)m_OutMediaType.pbFormat)->bmiHeader; } if (pBmpIn && pBmpOut && m_InMediaType.lSampleSize == m_OutMediaType.lSampleSize) { BYTE *pBufIn, *pBufOut; pIn->GetPointer(&pBufIn); pOut->GetPointer(&pBufOut); DWORD lSize = pIn->GetActualDataLength(); DWORD OutOffset = 0; if (*((int *)pBufIn) != 0xB0010000 && m_pMpeg4Sequence) { if (pIn->IsSyncPoint() == S_OK) { // I-VOP memcpy(pBufOut, m_pMpeg4Sequence, m_Mpeg4SequenceSize); OutOffset = m_Mpeg4SequenceSize; } } pOut->SetActualDataLength(lSize + OutOffset); memcpy(&pBufOut[OutOffset], pBufIn, lSize); LONGLONG UnitDuration = (10000000LL * m_FpsDen)/m_FpsNom; LONGLONG NormalStart = (m_SampleCnt * 10000000LL * m_FpsDen)/m_FpsNom; LONGLONG NormalEnd = ((m_SampleCnt + 1) * 10000000LL * m_FpsDen)/m_FpsNom; LONGLONG sTime, eTime; pOut->GetTime(&sTime, &eTime); int bSetTime = 0; LONGLONG sDuration = eTime - sTime; // simply set correct end time - seems to work here... if (eTime < sTime + UnitDuration) { eTime = sTime + UnitDuration; bSetTime = 1; } if (bSetTime) pOut->SetTime(&sTime, &eTime); #if 0 LONGLONG sTime=0, eTime=0; sTime = (m_SampleCnt * 10000000LL * m_FpsDen)/m_FpsNom; eTime = ((m_SampleCnt + 1) * 10000000LL * m_FpsDen)/m_FpsNom - 1; pOut->SetTime(&sTime, &eTime); #endif m_startTime = sTime; m_stopTime = eTime; m_SampleCnt ++; int CurPos = (int) ((double)(100.0 * m_SampleCnt/m_TotalFrames) + 0.5); if (m_Pass == 0) CurPos /= 2; else if (m_Pass == 2) CurPos = CurPos /2 + 50; if (m_MessageWnd) PostMessage(m_MessageWnd, PBM_SETPOS, CurPos, 0); hr = S_OK; } return hr; }