AviSplitter.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
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 //      UnRegisterSourceFilter(MEDIASUBTYPE_Avi);
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 // CAviSplitterFilter
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 //                      case BI_RLE8: mt.subtype = MEDIASUBTYPE_RGB8; break;
00210 //                      case BI_RLE4: mt.subtype = MEDIASUBTYPE_RGB4; break;
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         // reindex if needed
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 == 'pc' ||*/ 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; // TODO: find a better way...
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                                         // ASSERT(0);
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); // break;
00558 /*
00559                         DbgLog((LOG_TRACE, 0, _T("%d (%d): %I64d - %I64d, %I64d - %I64d (size = %d)"), 
00560                                 minTrack, (int)p->bSyncPoint,
00561                                 (p->rtStart)/10000, (p->rtStop)/10000, 
00562                                 (p->rtStart-m_rtStart)/10000, (p->rtStop-m_rtStart)/10000,
00563                                 size));
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 // IMediaSeeking
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 // IKeyFrameInfo
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 // CAviSourceFilter
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 // CAviSplitterOutputPin
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 

Generated on Tue Dec 13 14:47:10 2005 for guliverkli by  doxygen 1.4.5