00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include <mmreg.h>
00024 #include "AviFile.h"
00025 #include "AviReportWnd.h"
00026 #include "AviSplitter.h"
00027
00028 #ifdef REGISTER_FILTER
00029
00030 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
00031 {
00032 {&MEDIATYPE_Stream, &MEDIASUBTYPE_Avi},
00033 {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
00034 };
00035
00036 const AMOVIESETUP_PIN sudpPins[] =
00037 {
00038 {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
00039 {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
00040 };
00041
00042 const AMOVIESETUP_FILTER sudFilter[] =
00043 {
00044 {&__uuidof(CAviSplitterFilter), L"Avi Splitter", MERIT_NORMAL+1, countof(sudpPins), sudpPins},
00045 {&__uuidof(CAviSourceFilter), L"Avi Source", MERIT_NORMAL+1, 0, NULL},
00046 };
00047
00048 CFactoryTemplate g_Templates[] =
00049 {
00050 {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CAviSplitterFilter>, NULL, &sudFilter[0]},
00051 {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<CAviSourceFilter>, NULL, &sudFilter[1]},
00052 };
00053
00054 int g_cTemplates = countof(g_Templates);
00055
00056 STDAPI DllRegisterServer()
00057 {
00058 RegisterSourceFilter(
00059 CLSID_AsyncReader,
00060 MEDIASUBTYPE_Avi,
00061 _T("0,4,,52494646,8,4,41564920"),
00062 _T(".avi"), _T(".divx"), _T(".vp6"), NULL);
00063
00064 return AMovieDllRegisterServer2(TRUE);
00065 }
00066
00067 STDAPI DllUnregisterServer()
00068 {
00069
00070
00071 return AMovieDllRegisterServer2(FALSE);
00072 }
00073
00074 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
00075
00076 class CAviSplitterApp : public CWinApp
00077 {
00078 public:
00079 CAviSplitterApp() {}
00080
00081 BOOL InitInstance()
00082 {
00083 if(!__super::InitInstance()) return FALSE;
00084 DllEntryPoint(m_hInstance, DLL_PROCESS_ATTACH, 0);
00085 return TRUE;
00086 }
00087
00088 BOOL ExitInstance()
00089 {
00090 DllEntryPoint(m_hInstance, DLL_PROCESS_DETACH, 0);
00091 return __super::ExitInstance();
00092 }
00093
00094 void SetDefaultRegistryKey()
00095 {
00096 SetRegistryKey(_T("Gabest"));
00097 }
00098
00099 DECLARE_MESSAGE_MAP()
00100 };
00101
00102 BEGIN_MESSAGE_MAP(CAviSplitterApp, CWinApp)
00103 END_MESSAGE_MAP()
00104
00105 CAviSplitterApp theApp;
00106
00107 #endif
00108
00109
00110
00111
00112
00113 CAviSplitterFilter::CAviSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
00114 : CBaseSplitterFilter(NAME("CAviSplitterFilter"), pUnk, phr, __uuidof(this))
00115 , m_timeformat(TIME_FORMAT_MEDIA_TIME)
00116 {
00117 }
00118
00119 STDMETHODIMP CAviSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00120 {
00121 CheckPointer(ppv, E_POINTER);
00122
00123 *ppv = NULL;
00124
00125 return
00126 __super::NonDelegatingQueryInterface(riid, ppv);
00127 }
00128
00129 HRESULT CAviSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
00130 {
00131 CheckPointer(pAsyncReader, E_POINTER);
00132
00133 HRESULT hr = E_FAIL;
00134
00135 m_pFile.Free();
00136 m_tFrame.Free();
00137
00138 m_pFile.Attach(new CAviFile(pAsyncReader, hr));
00139 if(!m_pFile) return E_OUTOFMEMORY;
00140
00141 bool fShiftDown = !!(::GetKeyState(VK_SHIFT)&0x8000);
00142 bool fShowWarningText = !m_pFile->IsInterleaved(fShiftDown);
00143
00144 if(SUCCEEDED(hr) && (fShowWarningText || fShiftDown))
00145 {
00146 #ifdef REGISTER_FILTER
00147 AFX_MANAGE_STATE(AfxGetStaticModuleState());
00148 #endif
00149 bool fHideWarning = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("HideAviSplitterWarning"), 0);
00150
00151 if(!fHideWarning && !dynamic_cast<CAviSourceFilter*>(this) || fShiftDown)
00152 {
00153 CAviReportWnd wnd;
00154 fHideWarning = wnd.DoModal(m_pFile, fHideWarning, fShowWarningText);
00155 AfxGetApp()->WriteProfileInt(_T("Settings"), _T("HideAviSplitterWarning"), fHideWarning);
00156 }
00157
00158 if(fShowWarningText) hr = E_FAIL;
00159 }
00160
00161 if(FAILED(hr)) {m_pFile.Free(); return hr;}
00162
00163 m_rtNewStart = m_rtCurrent = 0;
00164 m_rtNewStop = m_rtStop = m_rtDuration = m_pFile->GetTotalTime();
00165
00166 bool fHasIndex = false;
00167
00168 for(DWORD i = 0; !fHasIndex && i < m_pFile->m_strms.GetCount(); i++)
00169 if(m_pFile->m_strms[i]->cs.GetCount() > 0)
00170 fHasIndex = true;
00171
00172 for(DWORD i = 0; i < m_pFile->m_strms.GetCount(); i++)
00173 {
00174 CAviFile::strm_t* s = m_pFile->m_strms[i];
00175
00176 if(fHasIndex && s->cs.GetCount() == 0) continue;
00177
00178 CMediaType mt;
00179 CArray<CMediaType> mts;
00180
00181 CStringW name, label;
00182
00183 if(s->strh.fccType == FCC('vids'))
00184 {
00185 label = L"Video";
00186
00187 ASSERT(s->strf.GetSize() >= sizeof(BITMAPINFOHEADER));
00188
00189 BITMAPINFOHEADER* pbmi = &((BITMAPINFO*)s->strf.GetData())->bmiHeader;
00190
00191 mt.majortype = MEDIATYPE_Video;
00192 mt.subtype = FOURCCMap(pbmi->biCompression);
00193 mt.formattype = FORMAT_VideoInfo;
00194 VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + s->strf.GetSize() - sizeof(BITMAPINFOHEADER));
00195 memset(mt.Format(), 0, mt.FormatLength());
00196 memcpy(&pvih->bmiHeader, s->strf.GetData(), s->strf.GetSize());
00197 if(s->strh.dwRate > 0) pvih->AvgTimePerFrame = 10000000i64 * s->strh.dwScale / s->strh.dwRate;
00198 switch(pbmi->biCompression)
00199 {
00200 case BI_RGB: case BI_BITFIELDS: mt.subtype =
00201 pbmi->biBitCount == 1 ? MEDIASUBTYPE_RGB1 :
00202 pbmi->biBitCount == 4 ? MEDIASUBTYPE_RGB4 :
00203 pbmi->biBitCount == 8 ? MEDIASUBTYPE_RGB8 :
00204 pbmi->biBitCount == 16 ? MEDIASUBTYPE_RGB565 :
00205 pbmi->biBitCount == 24 ? MEDIASUBTYPE_RGB24 :
00206 pbmi->biBitCount == 32 ? MEDIASUBTYPE_ARGB32 :
00207 MEDIASUBTYPE_NULL;
00208 break;
00209
00210
00211 }
00212
00213 if(s->cs.GetCount() && pvih->AvgTimePerFrame > 0)
00214 {
00215 __int64 size = 0;
00216 for(int i = 0; i < s->cs.GetCount(); i++)
00217 size += s->cs[i].orgsize;
00218 pvih->dwBitRate = size*8 / s->cs.GetCount() * 10000000i64 / pvih->AvgTimePerFrame;
00219 }
00220
00221 mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0
00222 ? s->strh.dwSuggestedBufferSize*3/2
00223 : (pvih->bmiHeader.biWidth*pvih->bmiHeader.biHeight*4));
00224 mts.Add(mt);
00225 }
00226 else if(s->strh.fccType == FCC('auds'))
00227 {
00228 label = L"Audio";
00229
00230 ASSERT(s->strf.GetSize() >= sizeof(WAVEFORMATEX)
00231 || s->strf.GetSize() == sizeof(PCMWAVEFORMAT));
00232
00233 WAVEFORMATEX* pwfe = (WAVEFORMATEX*)s->strf.GetData();
00234
00235 if(pwfe->nBlockAlign == 0) continue;
00236
00237 mt.majortype = MEDIATYPE_Audio;
00238 mt.subtype = FOURCCMap(pwfe->wFormatTag);
00239 mt.formattype = FORMAT_WaveFormatEx;
00240 mt.SetFormat(s->strf.GetData(), max(s->strf.GetSize(), sizeof(WAVEFORMATEX)));
00241 pwfe = (WAVEFORMATEX*)mt.Format();
00242 if(s->strf.GetSize() == sizeof(PCMWAVEFORMAT)) pwfe->cbSize = 0;
00243 if(pwfe->wFormatTag == WAVE_FORMAT_PCM) pwfe->nBlockAlign = pwfe->nChannels*pwfe->wBitsPerSample>>3;
00244 mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0
00245 ? s->strh.dwSuggestedBufferSize*3/2
00246 : (pwfe->nChannels*pwfe->nSamplesPerSec*32>>3));
00247 mts.Add(mt);
00248 }
00249 else if(s->strh.fccType == FCC('mids'))
00250 {
00251 label = L"Midi";
00252
00253 mt.majortype = MEDIATYPE_Midi;
00254 mt.subtype = MEDIASUBTYPE_NULL;
00255 mt.formattype = FORMAT_None;
00256 mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0
00257 ? s->strh.dwSuggestedBufferSize*3/2
00258 : (1024*1024));
00259 mts.Add(mt);
00260 }
00261 else if(s->strh.fccType == FCC('txts'))
00262 {
00263 label = L"Text";
00264
00265 mt.majortype = MEDIATYPE_Text;
00266 mt.subtype = MEDIASUBTYPE_NULL;
00267 mt.formattype = FORMAT_None;
00268 mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0
00269 ? s->strh.dwSuggestedBufferSize*3/2
00270 : (1024*1024));
00271 mts.Add(mt);
00272 }
00273 else if(s->strh.fccType == FCC('iavs'))
00274 {
00275 label = L"Interleaved";
00276
00277 ASSERT(s->strh.fccHandler == FCC('dvsd'));
00278
00279 mt.majortype = MEDIATYPE_Interleaved;
00280 mt.subtype = FOURCCMap(s->strh.fccHandler);
00281 mt.formattype = FORMAT_DvInfo;
00282 mt.SetFormat(s->strf.GetData(), max(s->strf.GetSize(), sizeof(DVINFO)));
00283 mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0
00284 ? s->strh.dwSuggestedBufferSize*3/2
00285 : (1024*1024));
00286 mts.Add(mt);
00287 }
00288
00289 if(mts.IsEmpty())
00290 {
00291 TRACE(_T("CAviSourceFilter: Unsupported stream (%d)\n"), i);
00292 continue;
00293 }
00294
00295 name.Format(L"%s %d", !s->strn.IsEmpty() ? CStringW(s->strn) : label, i);
00296
00297 HRESULT hr;
00298
00299 CAutoPtr<CBaseSplitterOutputPin> pPinOut(new CAviSplitterOutputPin(mts, name, this, this, &hr));
00300 AddOutputPin(i, pPinOut);
00301 }
00302
00303 POSITION pos = m_pFile->m_info.GetStartPosition();
00304 while(pos)
00305 {
00306 DWORD fcc;
00307 CStringA value;
00308 m_pFile->m_info.GetNextAssoc(pos, fcc, value);
00309
00310 switch(fcc)
00311 {
00312 case FCC('INAM'): SetProperty(L"TITL", CStringW(value)); break;
00313 case FCC('IART'): SetProperty(L"AUTH", CStringW(value)); break;
00314 case FCC('ICOP'): SetProperty(L"CPYR", CStringW(value)); break;
00315 case FCC('ISBJ'): SetProperty(L"DESC", CStringW(value)); break;
00316 }
00317 }
00318
00319 m_tFrame.Attach(new DWORD[m_pFile->m_avih.dwStreams]);
00320
00321 return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
00322 }
00323
00324 bool CAviSplitterFilter::DemuxInit()
00325 {
00326 if(!m_pFile) return(false);
00327
00328
00329
00330 bool fReIndex = false;
00331
00332 for(int i = 0; i < (int)m_pFile->m_avih.dwStreams && !fReIndex; i++)
00333 {
00334 if(m_pFile->m_strms[i]->cs.GetCount() == 0 && GetOutputPin(i))
00335 fReIndex = true;
00336 }
00337
00338 if(fReIndex)
00339 {
00340 m_pFile->EmptyIndex();
00341
00342 m_fAbort = false;
00343 m_nOpenProgress = 0;
00344
00345 m_rtDuration = 0;
00346
00347 CAutoVectorPtr<UINT64> pSize;
00348 pSize.Allocate(m_pFile->m_avih.dwStreams);
00349 memset((UINT64*)pSize, 0, sizeof(UINT64)*m_pFile->m_avih.dwStreams);
00350 m_pFile->Seek(0);
00351 ReIndex(m_pFile->GetLength(), pSize);
00352
00353 if(m_fAbort) m_pFile->EmptyIndex();
00354
00355 m_fAbort = false;
00356 m_nOpenProgress = 100;
00357 }
00358
00359 return(true);
00360 }
00361
00362 HRESULT CAviSplitterFilter::ReIndex(__int64 end, UINT64* pSize)
00363 {
00364 HRESULT hr = S_OK;
00365
00366 while(S_OK == hr && m_pFile->GetPos() < end && SUCCEEDED(hr) && !m_fAbort)
00367 {
00368 __int64 pos = m_pFile->GetPos();
00369
00370 DWORD id = 0, size;
00371 if(S_OK != m_pFile->Read(id) || id == 0)
00372 return E_FAIL;
00373
00374 if(id == FCC('RIFF') || id == FCC('LIST'))
00375 {
00376 if(S_OK != m_pFile->Read(size) || S_OK != m_pFile->Read(id))
00377 return E_FAIL;
00378
00379 size += (size&1) + 8;
00380
00381 if(id == FCC('AVI ') || id == FCC('AVIX') || id == FCC('movi') || id == FCC('rec '))
00382 hr = ReIndex(pos + size, pSize);
00383 }
00384 else
00385 {
00386 if(S_OK != m_pFile->Read(size))
00387 return E_FAIL;
00388
00389 DWORD TrackNumber = TRACKNUM(id);
00390
00391 if(TrackNumber < m_pFile->m_strms.GetCount())
00392 {
00393 CAviFile::strm_t* s = m_pFile->m_strms[TrackNumber];
00394
00395 WORD type = TRACKTYPE(id);
00396
00397 if(type == 'db' || type == 'dc' || type == 'wb'
00398 || type == 'iv' || type == '__' || type == 'xx')
00399 {
00400 CAviFile::strm_t::chunk c;
00401 c.filepos = pos;
00402 c.size = pSize[TrackNumber];
00403 c.orgsize = size;
00404 c.fKeyFrame = size > 0;
00405 c.fChunkHdr = true;
00406 s->cs.Add(c);
00407
00408 pSize[TrackNumber] += s->GetChunkSize(size);
00409
00410 REFERENCE_TIME rt = s->GetRefTime(s->cs.GetCount()-1, pSize[TrackNumber]);
00411 m_rtDuration = max(rt, m_rtDuration);
00412 }
00413 }
00414
00415 size += (size&1) + 8;
00416 }
00417
00418 m_pFile->Seek(pos + size);
00419
00420 m_nOpenProgress = m_pFile->GetPos()*100/m_pFile->GetLength();
00421
00422 DWORD cmd;
00423 if(CheckRequest(&cmd))
00424 {
00425 if(cmd == CMD_EXIT) m_fAbort = true;
00426 else Reply(S_OK);
00427 }
00428 }
00429
00430 return hr;
00431 }
00432
00433 void CAviSplitterFilter::DemuxSeek(REFERENCE_TIME rt)
00434 {
00435 memset((DWORD*)m_tFrame, 0, sizeof(DWORD)*m_pFile->m_avih.dwStreams);
00436 m_pFile->Seek(0);
00437
00438 DbgLog((LOG_TRACE, 0, _T("Seek: %I64d"), rt/10000));
00439
00440 if(rt > 0)
00441 {
00442 UINT64 minfp = _I64_MAX;
00443
00444 for(int j = 0; j < (int)m_pFile->m_strms.GetCount(); j++)
00445 {
00446 CAviFile::strm_t* s = m_pFile->m_strms[j];
00447
00448 int f = s->GetKeyFrame(rt);
00449 UINT64 fp = f >= 0 ? s->cs[f].filepos : m_pFile->GetLength();
00450
00451 if(!s->IsRawSubtitleStream())
00452 minfp = min(minfp, fp);
00453 }
00454
00455 for(int j = 0; j < (int)m_pFile->m_strms.GetCount(); j++)
00456 {
00457 CAviFile::strm_t* s = m_pFile->m_strms[j];
00458
00459 for(int i = 0; i < s->cs.GetCount(); i++)
00460 {
00461 CAviFile::strm_t::chunk& c = s->cs[i];
00462 if(c.filepos >= minfp)
00463 {
00464 m_tFrame[j] = i;
00465 break;
00466 }
00467 }
00468 }
00469
00470 DbgLog((LOG_TRACE, 0, _T("minfp: %I64d"), minfp));
00471 }
00472 }
00473
00474 bool CAviSplitterFilter::DemuxLoop()
00475 {
00476 HRESULT hr = S_OK;
00477
00478 int nTracks = (int)m_pFile->m_strms.GetCount();
00479
00480 CArray<BOOL> fDiscontinuity;
00481 fDiscontinuity.SetSize(nTracks);
00482 memset(fDiscontinuity.GetData(), 0, nTracks*sizeof(bool));
00483
00484 while(SUCCEEDED(hr) && !CheckRequest(NULL))
00485 {
00486 int minTrack = nTracks;
00487 UINT64 minFilePos = _I64_MAX;
00488
00489 for(int i = 0; i < nTracks; i++)
00490 {
00491 CAviFile::strm_t* s = m_pFile->m_strms[i];
00492
00493 DWORD f = m_tFrame[i];
00494 if(f >= (DWORD)s->cs.GetCount()) continue;
00495
00496 bool fUrgent = s->IsRawSubtitleStream();
00497
00498 if(fUrgent || s->cs[f].filepos < minFilePos)
00499 {
00500 minTrack = i;
00501 minFilePos = s->cs[f].filepos;
00502 }
00503
00504 if(fUrgent) break;
00505 }
00506
00507 if(minTrack == nTracks)
00508 break;
00509
00510 DWORD& f = m_tFrame[minTrack];
00511
00512 do
00513 {
00514 CAviFile::strm_t* s = m_pFile->m_strms[minTrack];
00515
00516 m_pFile->Seek(s->cs[f].filepos);
00517
00518 DWORD size = 0;
00519
00520 if(s->cs[f].fChunkHdr)
00521 {
00522 DWORD id = 0;
00523 if(S_OK != m_pFile->Read(id) || id == 0 || minTrack != TRACKNUM(id)
00524 || S_OK != m_pFile->Read(size))
00525 {
00526 fDiscontinuity[minTrack] = true;
00527 break;
00528 }
00529
00530 UINT64 expectedsize = -1;
00531 expectedsize = f < (DWORD)s->cs.GetCount()-1
00532 ? s->cs[f+1].size - s->cs[f].size
00533 : s->totalsize - s->cs[f].size;
00534
00535 if(expectedsize != s->GetChunkSize(size))
00536 {
00537 fDiscontinuity[minTrack] = true;
00538
00539 break;
00540 }
00541 }
00542 else
00543 {
00544 size = s->cs[f].orgsize;
00545 }
00546
00547 CAutoPtr<Packet> p(new Packet());
00548
00549 p->TrackNumber = minTrack;
00550 p->bSyncPoint = (BOOL)s->cs[f].fKeyFrame;
00551 p->bDiscontinuity = fDiscontinuity[minTrack];
00552 p->rtStart = s->GetRefTime(f, s->cs[f].size);
00553 p->rtStop = s->GetRefTime(f+1, f+1 < (DWORD)s->cs.GetCount() ? s->cs[f+1].size : s->totalsize);
00554 p->pData.SetSize(size);
00555
00556 if(S_OK != (hr = m_pFile->Read(p->pData.GetData(), p->pData.GetSize())))
00557 return(true);
00558
00559
00560
00561
00562
00563
00564
00565 hr = DeliverPacket(p);
00566
00567 fDiscontinuity[minTrack] = false;
00568 }
00569 while(0);
00570
00571 f++;
00572 }
00573
00574 return(true);
00575 }
00576
00577
00578
00579 STDMETHODIMP CAviSplitterFilter::GetDuration(LONGLONG* pDuration)
00580 {
00581 CheckPointer(pDuration, E_POINTER);
00582 CheckPointer(m_pFile, VFW_E_NOT_CONNECTED);
00583
00584 if(m_timeformat == TIME_FORMAT_FRAME)
00585 {
00586 for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
00587 {
00588 CAviFile::strm_t* s = m_pFile->m_strms[i];
00589 if(s->strh.fccType == FCC('vids'))
00590 {
00591 *pDuration = s->cs.GetCount();
00592 return S_OK;
00593 }
00594 }
00595
00596 return E_UNEXPECTED;
00597 }
00598
00599 return __super::GetDuration(pDuration);
00600 }
00601
00602
00603
00604 STDMETHODIMP CAviSplitterFilter::IsFormatSupported(const GUID* pFormat)
00605 {
00606 CheckPointer(pFormat, E_POINTER);
00607 HRESULT hr = __super::IsFormatSupported(pFormat);
00608 if(S_OK == hr) return hr;
00609 return *pFormat == TIME_FORMAT_FRAME ? S_OK : S_FALSE;
00610 }
00611
00612 STDMETHODIMP CAviSplitterFilter::GetTimeFormat(GUID* pFormat)
00613 {
00614 CheckPointer(pFormat, E_POINTER);
00615 *pFormat = m_timeformat;
00616 return S_OK;
00617 }
00618
00619 STDMETHODIMP CAviSplitterFilter::IsUsingTimeFormat(const GUID* pFormat)
00620 {
00621 CheckPointer(pFormat, E_POINTER);
00622 return *pFormat == m_timeformat ? S_OK : S_FALSE;
00623 }
00624
00625 STDMETHODIMP CAviSplitterFilter::SetTimeFormat(const GUID* pFormat)
00626 {
00627 CheckPointer(pFormat, E_POINTER);
00628 if(S_OK != IsFormatSupported(pFormat)) return E_FAIL;
00629 m_timeformat = *pFormat;
00630 return S_OK;
00631 }
00632
00633 STDMETHODIMP CAviSplitterFilter::GetStopPosition(LONGLONG* pStop)
00634 {
00635 CheckPointer(pStop, E_POINTER);
00636 if(FAILED(__super::GetStopPosition(pStop))) return E_FAIL;
00637 if(m_timeformat == TIME_FORMAT_MEDIA_TIME) return S_OK;
00638 LONGLONG rt = *pStop;
00639 if(FAILED(ConvertTimeFormat(pStop, &TIME_FORMAT_FRAME, rt, &TIME_FORMAT_MEDIA_TIME))) return E_FAIL;
00640 return S_OK;
00641 }
00642
00643 STDMETHODIMP CAviSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat)
00644 {
00645 CheckPointer(pTarget, E_POINTER);
00646
00647 const GUID& SourceFormat = pSourceFormat ? *pSourceFormat : m_timeformat;
00648 const GUID& TargetFormat = pTargetFormat ? *pTargetFormat : m_timeformat;
00649
00650 if(TargetFormat == SourceFormat)
00651 {
00652 *pTarget = Source;
00653 return S_OK;
00654 }
00655 else if(TargetFormat == TIME_FORMAT_FRAME && SourceFormat == TIME_FORMAT_MEDIA_TIME)
00656 {
00657 for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
00658 {
00659 CAviFile::strm_t* s = m_pFile->m_strms[i];
00660 if(s->strh.fccType == FCC('vids'))
00661 {
00662 *pTarget = s->GetFrame(Source);
00663 return S_OK;
00664 }
00665 }
00666 }
00667 else if(TargetFormat == TIME_FORMAT_MEDIA_TIME && SourceFormat == TIME_FORMAT_FRAME)
00668 {
00669 for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
00670 {
00671 CAviFile::strm_t* s = m_pFile->m_strms[i];
00672 if(s->strh.fccType == FCC('vids'))
00673 {
00674 if(Source < 0 || Source >= s->cs.GetCount()) return E_FAIL;
00675 CAviFile::strm_t::chunk& c = s->cs[(int)Source];
00676 *pTarget = s->GetRefTime((DWORD)Source, c.size);
00677 return S_OK;
00678 }
00679 }
00680 }
00681
00682 return E_FAIL;
00683 }
00684
00685 STDMETHODIMP CAviSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
00686 {
00687 HRESULT hr;
00688 if(FAILED(hr = __super::GetPositions(pCurrent, pStop)) || m_timeformat != TIME_FORMAT_FRAME)
00689 return hr;
00690
00691 if(pCurrent)
00692 if(FAILED(ConvertTimeFormat(pCurrent, &TIME_FORMAT_FRAME, *pCurrent, &TIME_FORMAT_MEDIA_TIME))) return E_FAIL;
00693 if(pStop)
00694 if(FAILED(ConvertTimeFormat(pStop, &TIME_FORMAT_FRAME, *pStop, &TIME_FORMAT_MEDIA_TIME))) return E_FAIL;
00695
00696 return S_OK;
00697 }
00698
00699 HRESULT CAviSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
00700 {
00701 if(m_timeformat != TIME_FORMAT_FRAME)
00702 return __super::SetPositionsInternal(id, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
00703
00704 if(!pCurrent && !pStop
00705 || (dwCurrentFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning
00706 && (dwStopFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
00707 return S_OK;
00708
00709 REFERENCE_TIME
00710 rtCurrent = m_rtCurrent,
00711 rtStop = m_rtStop;
00712
00713 if((dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
00714 && FAILED(ConvertTimeFormat(&rtCurrent, &TIME_FORMAT_FRAME, rtCurrent, &TIME_FORMAT_MEDIA_TIME)))
00715 return E_FAIL;
00716 if((dwStopFlags&AM_SEEKING_PositioningBitsMask)
00717 && FAILED(ConvertTimeFormat(&rtStop, &TIME_FORMAT_FRAME, rtStop, &TIME_FORMAT_MEDIA_TIME)))
00718 return E_FAIL;
00719
00720 if(pCurrent)
00721 switch(dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
00722 {
00723 case AM_SEEKING_NoPositioning: break;
00724 case AM_SEEKING_AbsolutePositioning: rtCurrent = *pCurrent; break;
00725 case AM_SEEKING_RelativePositioning: rtCurrent = rtCurrent + *pCurrent; break;
00726 case AM_SEEKING_IncrementalPositioning: rtCurrent = rtCurrent + *pCurrent; break;
00727 }
00728
00729 if(pStop)
00730 switch(dwStopFlags&AM_SEEKING_PositioningBitsMask)
00731 {
00732 case AM_SEEKING_NoPositioning: break;
00733 case AM_SEEKING_AbsolutePositioning: rtStop = *pStop; break;
00734 case AM_SEEKING_RelativePositioning: rtStop += *pStop; break;
00735 case AM_SEEKING_IncrementalPositioning: rtStop = rtCurrent + *pStop; break;
00736 }
00737
00738 if((dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
00739 && pCurrent)
00740 if(FAILED(ConvertTimeFormat(pCurrent, &TIME_FORMAT_MEDIA_TIME, rtCurrent, &TIME_FORMAT_FRAME))) return E_FAIL;
00741 if((dwStopFlags&AM_SEEKING_PositioningBitsMask)
00742 && pStop)
00743 if(FAILED(ConvertTimeFormat(pStop, &TIME_FORMAT_MEDIA_TIME, rtStop, &TIME_FORMAT_FRAME))) return E_FAIL;
00744
00745 return __super::SetPositionsInternal(id, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
00746 }
00747
00748
00749
00750 STDMETHODIMP CAviSplitterFilter::GetKeyFrameCount(UINT& nKFs)
00751 {
00752 if(!m_pFile) return E_UNEXPECTED;
00753
00754 HRESULT hr = S_OK;
00755
00756 nKFs = 0;
00757
00758 for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
00759 {
00760 CAviFile::strm_t* s = m_pFile->m_strms[i];
00761 if(s->strh.fccType != FCC('vids')) continue;
00762
00763 for(int j = 0; j < s->cs.GetCount(); j++)
00764 {
00765 CAviFile::strm_t::chunk& c = s->cs[j];
00766 if(c.fKeyFrame) nKFs++;
00767 }
00768
00769 if(nKFs == s->cs.GetCount())
00770 hr = S_FALSE;
00771
00772 break;
00773 }
00774
00775 return hr;
00776 }
00777
00778 STDMETHODIMP CAviSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
00779 {
00780 CheckPointer(pFormat, E_POINTER);
00781 CheckPointer(pKFs, E_POINTER);
00782
00783 if(!m_pFile) return E_UNEXPECTED;
00784 if(*pFormat != TIME_FORMAT_MEDIA_TIME && *pFormat != TIME_FORMAT_FRAME) return E_INVALIDARG;
00785
00786 UINT nKFsTmp = 0;
00787
00788 for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
00789 {
00790 CAviFile::strm_t* s = m_pFile->m_strms[i];
00791 if(s->strh.fccType != FCC('vids')) continue;
00792
00793 bool fConvertToRefTime = !!(*pFormat == TIME_FORMAT_MEDIA_TIME);
00794
00795 for(int j = 0; j < s->cs.GetCount() && nKFsTmp < nKFs; j++)
00796 {
00797 if(s->cs[j].fKeyFrame)
00798 pKFs[nKFsTmp++] = fConvertToRefTime ? s->GetRefTime(j, s->cs[j].size) : j;
00799 }
00800
00801 break;
00802 }
00803
00804 nKFs = nKFsTmp;
00805
00806 return S_OK;
00807 }
00808
00809
00810
00811
00812
00813 CAviSourceFilter::CAviSourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
00814 : CAviSplitterFilter(pUnk, phr)
00815 {
00816 m_clsid = __uuidof(this);
00817 m_pInput.Free();
00818 }
00819
00820
00821
00822
00823
00824 CAviSplitterOutputPin::CAviSplitterOutputPin(CArray<CMediaType>& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00825 : CBaseSplitterOutputPin(mts, pName, pFilter, pLock, phr)
00826 {
00827 }
00828
00829 HRESULT CAviSplitterOutputPin::CheckConnect(IPin* pPin)
00830 {
00831 int iPosition = 0;
00832 CMediaType mt;
00833 while(S_OK == GetMediaType(iPosition++, &mt))
00834 {
00835 if(mt.majortype == MEDIATYPE_Video
00836 && (mt.subtype == FOURCCMap(FCC('IV32'))
00837 || mt.subtype == FOURCCMap(FCC('IV31'))
00838 || mt.subtype == FOURCCMap(FCC('IF09'))))
00839 {
00840 CLSID clsid = GetCLSID(GetFilterFromPin(pPin));
00841 if(clsid == CLSID_VideoMixingRenderer || clsid == CLSID_OverlayMixer)
00842 return E_FAIL;
00843 }
00844
00845 mt.InitMediaType();
00846 }
00847
00848 return __super::CheckConnect(pPin);
00849 }
00850