- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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