- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# Mpeg2DecFilter.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 <math.h>
    00024 #include <atlbase.h>
    00025 #include <ks.h>
    00026 #include <ksmedia.h>
    00027 #include "libmpeg2.h"
    00028 #include "Mpeg2DecFilter.h"
    00029
    00030 #include "..\..\..\DSUtil\DSUtil.h"
    00031 #include "..\..\..\DSUtil\MediaTypes.h"
    00032
    00033 #include <initguid.h>
    00034 #include "..\..\..\..\include\moreuuids.h"
    00035 #include "..\..\..\..\include\matroska\matroska.h"
    00036
    00037 #ifdef REGISTER_FILTER
    00038
    00039 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
    00040 {
    00041         {&MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_MPEG2_VIDEO},
    00042         {&MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_MPEG2_VIDEO},
    00043         {&MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_MPEG2_VIDEO},
    00044         {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG2_VIDEO},
    00045         {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Packet},
    00046         {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Payload},
    00047 };
    00048
    00049 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
    00050 {
    00051         {&MEDIATYPE_Video, &MEDIASUBTYPE_IYUV},
    00052 };
    00053
    00054 const AMOVIESETUP_PIN sudpPins[] =
    00055 {
    00056     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
    00057     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
    00058 };
    00059
    00060 const AMOVIESETUP_FILTER sudFilter[] =
    00061 {
    00062         {&__uuidof(CMpeg2DecFilter), L"Mpeg2Dec Filter", 0x40000002, countof(sudpPins), sudpPins},
    00063 };
    00064
    00065 CFactoryTemplate g_Templates[] =
    00066 {
    00067     {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CMpeg2DecFilter>, NULL, &sudFilter[0]},
    00068 };
    00069
    00070 int g_cTemplates = countof(g_Templates);
    00071
    00072 STDAPI DllRegisterServer()
    00073 {
    00074         return AMovieDllRegisterServer2(TRUE);
    00075 }
    00076
    00077 STDAPI DllUnregisterServer()
    00078 {
    00079         return AMovieDllRegisterServer2(FALSE);
    00080 }
    00081
    00082 //
    00083
    00084 #include "..\..\..\..\include\detours\detours.h"
    00085
    00086 DETOUR_TRAMPOLINE(BOOL WINAPI Real_IsDebuggerPresent(), IsDebuggerPresent);
    00087 BOOL WINAPI Mine_IsDebuggerPresent()
    00088 {
    00089         TRACE(_T("Oops, somebody was trying to be naughty! (called IsDebuggerPresent)\n"));
    00090         return FALSE;
    00091 }
    00092
    00093 DETOUR_TRAMPOLINE(LONG WINAPI Real_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam), ChangeDisplaySettingsExA);
    00094 DETOUR_TRAMPOLINE(LONG WINAPI Real_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam), ChangeDisplaySettingsExW);
    00095 LONG WINAPI Mine_ChangeDisplaySettingsEx(LONG ret, DWORD dwFlags, LPVOID lParam)
    00096 {
    00097         if(dwFlags&CDS_VIDEOPARAMETERS)
    00098         {
    00099                 VIDEOPARAMETERS* vp = (VIDEOPARAMETERS*)lParam;
    00100
    00101                 if(vp->Guid == GUIDFromCString(_T("{02C62061-1097-11d1-920F-00A024DF156E}"))
    00102                 && (vp->dwFlags&VP_FLAGS_COPYPROTECT))
    00103                 {
    00104                         if(vp->dwCommand == VP_COMMAND_GET)
    00105                         {
    00106                                 if((vp->dwTVStandard&VP_TV_STANDARD_WIN_VGA) && vp->dwTVStandard != VP_TV_STANDARD_WIN_VGA)
    00107                                 {
    00108                                         TRACE(_T("Ooops, tv-out enabled? macrovision checks suck..."));
    00109                                         vp->dwTVStandard = VP_TV_STANDARD_WIN_VGA;
    00110                                 }
    00111                         }
    00112                         else if(vp->dwCommand == VP_COMMAND_SET)
    00113                         {
    00114                                 TRACE(_T("Ooops, as I already told ya, no need for any macrovision bs here"));
    00115                                 return 0;
    00116                         }
    00117                 }
    00118         }
    00119
    00120         return ret;
    00121 }
    00122 LONG WINAPI Mine_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam)
    00123 {
    00124         return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExA(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam);
    00125 }
    00126 LONG WINAPI Mine_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam)
    00127 {
    00128         return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam);
    00129 }
    00130
    00131 bool fDetourInited = false;
    00132
    00133 //
    00134
    00135 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
    00136
    00137 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    00138 {
    00139         if(!fDetourInited)
    00140         {
    00141                 DetourFunctionWithTrampoline((PBYTE)Real_IsDebuggerPresent, (PBYTE)Mine_IsDebuggerPresent);
    00142                 DetourFunctionWithTrampoline((PBYTE)Real_ChangeDisplaySettingsExA, (PBYTE)Mine_ChangeDisplaySettingsExA);
    00143                 DetourFunctionWithTrampoline((PBYTE)Real_ChangeDisplaySettingsExW, (PBYTE)Mine_ChangeDisplaySettingsExW);
    00144                 fDetourInited = true;
    00145         }
    00146
    00147         return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
    00148 }
    00149
    00150 #endif
    00151
    00152 //
    00153 // CMpeg2DecFilter
    00154 //
    00155
    00156 CMpeg2DecFilter::CMpeg2DecFilter(LPUNKNOWN lpunk, HRESULT* phr)
    00157         : CBaseVideoFilter(NAME("CMpeg2DecFilter"), lpunk, phr, __uuidof(this))
    00158         , m_fWaitForKeyFrame(true)
    00159 {
    00160         delete m_pInput;
    00161
    00162         if(FAILED(*phr)) return;
    00163
    00164         if(!(m_pInput = new CMpeg2DecInputPin(this, phr, L"Video"))) *phr = E_OUTOFMEMORY;
    00165         if(FAILED(*phr)) return;
    00166
    00167         if(!(m_pSubpicInput = new CSubpicInputPin(this, phr))) *phr = E_OUTOFMEMORY;
    00168         if(FAILED(*phr)) return;
    00169
    00170         if(!(m_pClosedCaptionOutput = new CClosedCaptionOutputPin(this, m_pLock, phr))) *phr = E_OUTOFMEMORY;
    00171         if(FAILED(*phr)) return;
    00172
    00173         SetDeinterlaceMethod(DIAuto);
    00174         SetBrightness(0.0);
    00175         SetContrast(1.0);
    00176         SetHue(0.0);
    00177         SetSaturation(1.0);
    00178         EnableForcedSubtitles(true);
    00179         EnablePlanarYUV(true);
    00180
    00181         m_rate.Rate = 10000;
    00182         m_rate.StartTime = 0;
    00183 }
    00184
    00185 CMpeg2DecFilter::~CMpeg2DecFilter()
    00186 {
    00187         delete m_pSubpicInput;
    00188         delete m_pClosedCaptionOutput;
    00189 }
    00190
    00191 STDMETHODIMP CMpeg2DecFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00192 {
    00193         return
    00194                 QI(IMpeg2DecFilter)
    00195                  __super::NonDelegatingQueryInterface(riid, ppv);
    00196 }
    00197
    00198 int CMpeg2DecFilter::GetPinCount()
    00199 {
    00200         return 4;
    00201 }
    00202
    00203 CBasePin* CMpeg2DecFilter::GetPin(int n)
    00204 {
    00205         switch(n)
    00206         {
    00207         case 0: return m_pInput;
    00208         case 1: return m_pOutput;
    00209         case 2: return m_pSubpicInput;
    00210         case 3: return m_pClosedCaptionOutput;
    00211         }
    00212         return NULL;
    00213 }
    00214
    00215 HRESULT CMpeg2DecFilter::EndOfStream()
    00216 {
    00217         CAutoLock cAutoLock(&m_csReceive);
    00218         m_pClosedCaptionOutput->EndOfStream();
    00219         return __super::EndOfStream();
    00220 }
    00221
    00222 HRESULT CMpeg2DecFilter::BeginFlush()
    00223 {
    00224         m_pClosedCaptionOutput->DeliverBeginFlush();
    00225         return __super::BeginFlush();
    00226 }
    00227
    00228 HRESULT CMpeg2DecFilter::EndFlush()
    00229 {
    00230         m_pClosedCaptionOutput->DeliverEndFlush();
    00231         return __super::EndFlush();
    00232 }
    00233
    00234 HRESULT CMpeg2DecFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
    00235 {
    00236         CAutoLock cAutoLock(&m_csReceive);
    00237         m_pClosedCaptionOutput->DeliverNewSegment(tStart, tStop, dRate);
    00238         m_fDropFrames = false;
    00239         return __super::NewSegment(tStart, tStop, dRate);
    00240 }
    00241
    00242 void CMpeg2DecFilter::InputTypeChanged()
    00243 {
    00244         CAutoLock cAutoLock(&m_csReceive);
    00245
    00246         TRACE(_T("ResetMpeg2Decoder()\n"));
    00247
    00248         for(int i = 0; i < countof(m_dec->m_pictures); i++)
    00249         {
    00250                 m_dec->m_pictures[i].rtStart = m_dec->m_pictures[i].rtStop = _I64_MIN+1;
    00251                 m_dec->m_pictures[i].fDelivered = false;
    00252                 m_dec->m_pictures[i].flags &= ~PIC_MASK_CODING_TYPE;
    00253         }
    00254
    00255         CMediaType& mt = m_pInput->CurrentMediaType();
    00256
    00257         BYTE* pSequenceHeader = NULL;
    00258         DWORD cbSequenceHeader = 0;
    00259
    00260         if(mt.formattype == FORMAT_MPEGVideo)
    00261         {
    00262                 pSequenceHeader = ((MPEG1VIDEOINFO*)mt.Format())->bSequenceHeader;
    00263                 cbSequenceHeader = ((MPEG1VIDEOINFO*)mt.Format())->cbSequenceHeader;
    00264         }
    00265         else if(mt.formattype == FORMAT_MPEG2_VIDEO)
    00266         {
    00267                 pSequenceHeader = (BYTE*)((MPEG2VIDEOINFO*)mt.Format())->dwSequenceHeader;
    00268                 cbSequenceHeader = ((MPEG2VIDEOINFO*)mt.Format())->cbSequenceHeader;
    00269         }
    00270
    00271         m_dec->mpeg2_close();
    00272         m_dec->mpeg2_init();
    00273
    00274         m_dec->mpeg2_buffer(pSequenceHeader, pSequenceHeader + cbSequenceHeader);
    00275
    00276         m_fWaitForKeyFrame = true;
    00277
    00278         m_fFilm = false;
    00279         m_fb.flags = 0;
    00280 }
    00281
    00282 HRESULT CMpeg2DecFilter::Transform(IMediaSample* pIn)
    00283 {
    00284         HRESULT hr;
    00285
    00286         BYTE* pDataIn = NULL;
    00287         if(FAILED(hr = pIn->GetPointer(&pDataIn)))
    00288                 return hr;
    00289
    00290         long len = pIn->GetActualDataLength();
    00291
    00292         ((CDeCSSInputPin*)m_pInput)->StripPacket(pDataIn, len);
    00293
    00294         if(pIn->IsDiscontinuity() == S_OK)
    00295         {
    00296                 InputTypeChanged();
    00297         }
    00298
    00299         REFERENCE_TIME rtStart = _I64_MIN, rtStop = _I64_MIN;
    00300         hr = pIn->GetTime(&rtStart, &rtStop);
    00301         if(FAILED(hr)) rtStart = rtStop = _I64_MIN;
    00302
    00303         while(len >= 0)
    00304         {
    00305                 mpeg2_state_t state = m_dec->mpeg2_parse();
    00306
    00307                 __asm emms; // this one is missing somewhere in the precompiled mmx obj files
    00308
    00309                 switch(state)
    00310                 {
    00311                 case STATE_BUFFER:
    00312                         if(len == 0) len = -1;
    00313                         else {m_dec->mpeg2_buffer(pDataIn, pDataIn + len); len = 0;}
    00314                         break;
    00315                 case STATE_INVALID:
    00316                         TRACE(_T("STATE_INVALID\n"));
    00317 //                      if(m_fWaitForKeyFrame)
    00318 //                              ResetMpeg2Decoder();
    00319                         break;
    00320                 case STATE_GOP:
    00321                         // TRACE(_T("STATE_GOP\n"));
    00322                         if(m_dec->m_info.m_user_data_len > 4 && *(DWORD*)m_dec->m_info.m_user_data == 0xf8014343
    00323                         && m_pClosedCaptionOutput->IsConnected())
    00324                         {
    00325                                 CComPtr<IMediaSample> pSample;
    00326                                 m_pClosedCaptionOutput->GetDeliveryBuffer(&pSample, NULL, NULL, 0);
    00327                                 BYTE* pData = NULL;
    00328                                 pSample->GetPointer(&pData);
    00329                                 *(DWORD*)pData = 0xb2010000;
    00330                                 memcpy(pData + 4, m_dec->m_info.m_user_data, m_dec->m_info.m_user_data_len);
    00331                                 pSample->SetActualDataLength(m_dec->m_info.m_user_data_len + 4);
    00332                                 m_pClosedCaptionOutput->Deliver(pSample);
    00333                         }
    00334                         break;
    00335                 case STATE_SEQUENCE:
    00336                         TRACE(_T("STATE_SEQUENCE\n"));
    00337                         m_AvgTimePerFrame = 10i64 * m_dec->m_info.m_sequence->frame_period / 27;
    00338                         if(m_AvgTimePerFrame == 0) m_AvgTimePerFrame = ((VIDEOINFOHEADER*)m_pInput->CurrentMediaType().Format())->AvgTimePerFrame;
    00339                         break;
    00340                 case STATE_PICTURE:
    00341 /*                      {
    00342                         TCHAR frametype[] = {'?','I', 'P', 'B', 'D'};
    00343                         TRACE(_T("STATE_PICTURE %010I64d [%c]\n"), rtStart, frametype[m_dec->m_picture->flags&PIC_MASK_CODING_TYPE]);
    00344                         }
    00345 */                      m_dec->m_picture->rtStart = rtStart;
    00346                         rtStart = _I64_MIN;
    00347                         m_dec->m_picture->fDelivered = false;
    00348
    00349                         m_dec->mpeg2_skip(m_fDropFrames && (m_dec->m_picture->flags&PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B);
    00350
    00351                         break;
    00352                 case STATE_SLICE:
    00353                 case STATE_END:
    00354                         {
    00355                                 mpeg2_picture_t* picture = m_dec->m_info.m_display_picture;
    00356                                 mpeg2_picture_t* picture_2nd = m_dec->m_info.m_display_picture_2nd;
    00357                                 mpeg2_fbuf_t* fbuf = m_dec->m_info.m_display_fbuf;
    00358
    00359                                 if(picture && fbuf && !(picture->flags&PIC_FLAG_SKIP))
    00360                                 {
    00361                                         ASSERT(!picture->fDelivered);
    00362
    00363                                         // start - end
    00364
    00365                                         m_fb.rtStart = picture->rtStart;
    00366                                         if(m_fb.rtStart == _I64_MIN) m_fb.rtStart = m_fb.rtStop;
    00367                                         m_fb.rtStop = m_fb.rtStart + m_AvgTimePerFrame * picture->nb_fields / (picture_2nd ? 1 : 2);
    00368
    00369                                         REFERENCE_TIME rtStart = m_fb.rtStart;
    00370                                         REFERENCE_TIME rtStop = m_fb.rtStop;
    00371
    00372                                         // flags
    00373
    00374                                         if(!(m_dec->m_info.m_sequence->flags&SEQ_FLAG_PROGRESSIVE_SEQUENCE)
    00375                                         && (picture->flags&PIC_FLAG_PROGRESSIVE_FRAME))
    00376                                         {
    00377                                                 if(!m_fFilm
    00378                                                 && (picture->flags&PIC_FLAG_REPEAT_FIRST_FIELD)
    00379                                                 && !(m_fb.flags&PIC_FLAG_REPEAT_FIRST_FIELD))
    00380                                                 {
    00381                                                         TRACE(_T("m_fFilm = true\n"));
    00382                                                         m_fFilm = true;
    00383                                                 }
    00384                                                 else if(m_fFilm
    00385                                                 && !(picture->flags&PIC_FLAG_REPEAT_FIRST_FIELD)
    00386                                                 && !(m_fb.flags&PIC_FLAG_REPEAT_FIRST_FIELD))
    00387                                                 {
    00388                                                         TRACE(_T("m_fFilm = false\n"));
    00389                                                         m_fFilm = false;
    00390                                                 }
    00391                                         }
    00392
    00393                                         m_fb.flags = picture->flags;
    00394
    00395 ASSERT(!(m_fb.flags&PIC_FLAG_SKIP));
    00396
    00397                                         // frame buffer
    00398
    00399                                         int w = m_dec->m_info.m_sequence->picture_width;
    00400                                         int h = m_dec->m_info.m_sequence->picture_height;
    00401                                         int pitch = m_dec->m_info.m_sequence->width;
    00402
    00403                                         if(m_fb.w != w || m_fb.h != h || m_fb.pitch != pitch)
    00404                                                 m_fb.alloc(w, h, pitch);
    00405
    00406                                         // deinterlace
    00407
    00408                                         ditype di = GetDeinterlaceMethod();
    00409
    00410                                         if(di == DIAuto || di != DIWeave && di != DIBlend && di != DIBob)
    00411                                         {
    00412                                                 if(!!(m_dec->m_info.m_sequence->flags&SEQ_FLAG_PROGRESSIVE_SEQUENCE))
    00413                                                         di = DIWeave; // hurray!
    00414                                                 else if(m_fFilm)
    00415                                                         di = DIWeave; // we are lucky
    00416                                                 else if(!(m_fb.flags&PIC_FLAG_PROGRESSIVE_FRAME))
    00417                                                         di = DIBlend; // ok, clear thing
    00418                                                 else
    00419                                                         // big trouble here, the progressive_frame bit is not reliable :'(
    00420                                                         // frames without temporal field diffs can be only detected when ntsc
    00421                                                         // uses the repeat field flag (signaled with m_fFilm), if it's not set
    00422                                                         // or we have pal then we might end up blending the fields unnecessarily...
    00423                                                         di = DIBlend;
    00424                                                         // TODO: find out if the pic is really interlaced by analysing it
    00425                                         }
    00426
    00427                                         if(di == DIWeave)
    00428                                         {
    00429                                                 BitBltFromI420ToI420(w, h,
    00430                                                         m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], pitch,
    00431                                                         fbuf->buf[0], fbuf->buf[1], fbuf->buf[2], pitch);
    00432                                         }
    00433                                         else if(di == DIBlend)
    00434                                         {
    00435                                                 DeinterlaceBlend(m_fb.buf[0], fbuf->buf[0], w, h, pitch, pitch);
    00436                                                 DeinterlaceBlend(m_fb.buf[1], fbuf->buf[1], w/2, h/2, pitch/2, pitch/2);
    00437                                                 DeinterlaceBlend(m_fb.buf[2], fbuf->buf[2], w/2, h/2, pitch/2, pitch/2);
    00438                                         }
    00439                                         else if(di == DIBob)
    00440                                         {
    00441                                                 if(m_fb.flags&PIC_FLAG_TOP_FIELD_FIRST)
    00442                                                 {
    00443                                                         BitBltFromRGBToRGB(w, h/2, m_fb.buf[0], pitch*2, 8, fbuf->buf[0], pitch*2, 8);
    00444                                                         AvgLines8(m_fb.buf[0], h, pitch);
    00445                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1], pitch, 8, fbuf->buf[1], pitch, 8);
    00446                                                         AvgLines8(m_fb.buf[1], h/2, pitch/2);
    00447                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2], pitch, 8, fbuf->buf[2], pitch, 8);
    00448                                                         AvgLines8(m_fb.buf[2], h/2, pitch/2);
    00449                                                 }
    00450                                                 else
    00451                                                 {
    00452                                                         BitBltFromRGBToRGB(w, h/2, m_fb.buf[0]+pitch, pitch*2, 8, fbuf->buf[0]+pitch, pitch*2, 8);
    00453                                                         AvgLines8(m_fb.buf[0]+pitch, h-1, pitch);
    00454                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1]+pitch/2, pitch, 8, fbuf->buf[1]+pitch/2, pitch, 8);
    00455                                                         AvgLines8(m_fb.buf[1]+pitch/2, (h-1)/2, pitch/2);
    00456                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2]+pitch/2, pitch, 8, fbuf->buf[2]+pitch/2, pitch, 8);
    00457                                                         AvgLines8(m_fb.buf[2]+pitch/2, (h-1)/2, pitch/2);
    00458                                                 }
    00459
    00460                                                 m_fb.rtStart = rtStart;
    00461                                                 m_fb.rtStop = (rtStart + rtStop) / 2;
    00462                                         }
    00463
    00464                                         // postproc
    00465
    00466                                         ApplyBrContHueSat(m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], w, h, pitch);
    00467
    00468                                         // deliver
    00469
    00470                                         picture->fDelivered = true;
    00471
    00472                                         if(FAILED(hr = Deliver(false)))
    00473                                                 return hr;
    00474
    00475                                         // spec code for bob
    00476
    00477                                         if(di == DIBob)
    00478                                         {
    00479                                                 if(m_fb.flags&PIC_FLAG_TOP_FIELD_FIRST)
    00480                                                 {
    00481                                                         BitBltFromRGBToRGB(w, h/2, m_fb.buf[0]+pitch, pitch*2, 8, fbuf->buf[0]+pitch, pitch*2, 8);
    00482                                                         AvgLines8(m_fb.buf[0]+pitch, h-1, pitch);
    00483                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1]+pitch/2, pitch, 8, fbuf->buf[1]+pitch/2, pitch, 8);
    00484                                                         AvgLines8(m_fb.buf[1]+pitch/2, (h-1)/2, pitch/2);
    00485                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2]+pitch/2, pitch, 8, fbuf->buf[2]+pitch/2, pitch, 8);
    00486                                                         AvgLines8(m_fb.buf[2]+pitch/2, (h-1)/2, pitch/2);
    00487                                                 }
    00488                                                 else
    00489                                                 {
    00490                                                         BitBltFromRGBToRGB(w, h/2, m_fb.buf[0], pitch*2, 8, fbuf->buf[0], pitch*2, 8);
    00491                                                         AvgLines8(m_fb.buf[0], h, pitch);
    00492                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1], pitch, 8, fbuf->buf[1], pitch, 8);
    00493                                                         AvgLines8(m_fb.buf[1], h/2, pitch/2);
    00494                                                         BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2], pitch, 8, fbuf->buf[2], pitch, 8);
    00495                                                         AvgLines8(m_fb.buf[2], h/2, pitch/2);
    00496                                                 }
    00497
    00498                                                 m_fb.rtStart = (rtStart + rtStop) / 2;
    00499                                                 m_fb.rtStop = rtStop;
    00500
    00501                                                 // postproc
    00502
    00503                                                 ApplyBrContHueSat(m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], w, h, pitch);
    00504
    00505                                                 // deliver
    00506
    00507                                                 picture->fDelivered = true;
    00508
    00509                                                 if(FAILED(hr = Deliver(false)))
    00510                                                         return hr;
    00511                                         }
    00512                                 }
    00513                         }
    00514                         break;
    00515                 default:
    00516                     break;
    00517                 }
    00518     }
    00519
    00520         return S_OK;
    00521 }
    00522
    00523 HRESULT CMpeg2DecFilter::Deliver(bool fRepeatLast)
    00524 {
    00525         CAutoLock cAutoLock(&m_csReceive);
    00526
    00527         if((m_fb.flags&PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I)
    00528                 m_fWaitForKeyFrame = false;
    00529
    00530         TCHAR frametype[] = {'?','I', 'P', 'B', 'D'};
    00531 //      TRACE(_T("%010I64d - %010I64d [%c] [prsq %d prfr %d tff %d rff %d nb_fields %d ref %d] (%dx%d/%dx%d)\n"),
    00532
    00533         TRACE(_T("%010I64d - %010I64d [%c] [prsq %d prfr %d tff %d rff %d] (%dx%d %d) (preroll %d)\n"),
    00534                 m_fb.rtStart, m_fb.rtStop,
    00535                 frametype[m_fb.flags&PIC_MASK_CODING_TYPE],
    00536                 !!(m_dec->m_info.m_sequence->flags&SEQ_FLAG_PROGRESSIVE_SEQUENCE),
    00537                 !!(m_fb.flags&PIC_FLAG_PROGRESSIVE_FRAME),
    00538                 !!(m_fb.flags&PIC_FLAG_TOP_FIELD_FIRST),
    00539                 !!(m_fb.flags&PIC_FLAG_REPEAT_FIRST_FIELD),
    00540 //              m_dec->m_info.m_display_picture->nb_fields,
    00541 //              m_dec->m_info.m_display_picture->temporal_reference,
    00542                 m_fb.w, m_fb.h, m_fb.pitch,
    00543                 !!(m_fb.rtStart < 0 || m_fWaitForKeyFrame));
    00544
    00545         if(m_fb.rtStart < 0 || m_fWaitForKeyFrame)
    00546                 return S_OK;
    00547
    00548         HRESULT hr;
    00549
    00550         CComPtr<IMediaSample> pOut;
    00551         BYTE* pDataOut = NULL;
    00552         if(FAILED(hr = GetDeliveryBuffer(m_fb.w, m_fb.h, &pOut))
    00553         || FAILED(hr = pOut->GetPointer(&pDataOut)))
    00554                 return hr;
    00555
    00556         {
    00557                 CMpeg2DecInputPin* pPin = (CMpeg2DecInputPin*)m_pInput;
    00558                 CAutoLock cAutoLock(&pPin->m_csRateLock);
    00559                 if(m_rate.Rate != pPin->m_ratechange.Rate)
    00560                 {
    00561                         m_rate.Rate = pPin->m_ratechange.Rate;
    00562                         m_rate.StartTime = m_fb.rtStart;
    00563                 }
    00564         }
    00565
    00566         REFERENCE_TIME rtStart = m_fb.rtStart;
    00567         REFERENCE_TIME rtStop = m_fb.rtStop;
    00568         rtStart = m_rate.StartTime + (rtStart - m_rate.StartTime) * m_rate.Rate / 10000;
    00569         rtStop = m_rate.StartTime + (rtStop - m_rate.StartTime) * m_rate.Rate / 10000;
    00570
    00571         pOut->SetTime(&rtStart, &rtStop);
    00572         pOut->SetMediaTime(NULL, NULL);
    00573
    00574         if(m_fb.h == 1088)
    00575         {
    00576                 memset(m_fb.buf[0] + m_fb.w*(m_fb.h-8), 0xff, m_fb.w*8);
    00577                 memset(m_fb.buf[1] + m_fb.w*(m_fb.h-8)/4, 0x80, m_fb.w*8/4);
    00578                 memset(m_fb.buf[2] + m_fb.w*(m_fb.h-8)/4, 0x80, m_fb.w*8/4);
    00579         }
    00580
    00581         BYTE** buf = &m_fb.buf[0];
    00582
    00583         if(m_pSubpicInput->HasAnythingToRender(m_fb.rtStart))
    00584         {
    00585                 BitBltFromI420ToI420(m_fb.w, m_fb.h,
    00586                         m_fb.buf[3], m_fb.buf[4], m_fb.buf[5], m_fb.pitch,
    00587                         m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], m_fb.pitch);
    00588
    00589                 buf = &m_fb.buf[3];
    00590
    00591                 m_pSubpicInput->RenderSubpics(m_fb.rtStart, buf, m_fb.pitch, m_fb.h);
    00592         }
    00593
    00594         CopyBuffer(pDataOut, buf, (m_fb.w+7)&~7, m_fb.h, m_fb.pitch, MEDIASUBTYPE_I420);
    00595
    00596         if(FAILED(hr = m_pOutput->Deliver(pOut)))
    00597                 return hr;
    00598
    00599         return S_OK;
    00600 }
    00601
    00602 #include "..\..\..\..\include\IFilterVersion.h"
    00603
    00604 [uuid("04FE9017-F873-410E-871E-AB91661A4EF7")]
    00605 struct ffdshow {};
    00606 [uuid("93A22E7A-5091-45ef-BA61-6DA26156A5D0")]
    00607 struct dvs {};
    00608 [uuid("9852A670-F845-491b-9BE6-EBD841B8A613")]
    00609 struct dvsauto {};
    00610 [uuid("fd501043-8ebe-11ce-8183-00aa00577da1")]
    00611 struct dladapter {};
    00612
    00613 HRESULT CMpeg2DecFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
    00614 {
    00615         if(dir == PINDIR_OUTPUT)
    00616         {
    00617                 if(GetCLSID(m_pInput->GetConnected()) == CLSID_DVDNavigator)
    00618                 {
    00619                         // one of these needed for dynamic format changes
    00620
    00621                         CLSID clsid = GetCLSID(pPin);
    00622
    00623                         DWORD ver = 0;
    00624                         if(CComQIPtr<IFilterVersion> pFV = GetFilterFromPin(pPin))
    00625                                 ver = pFV->GetFilterVersion();
    00626
    00627                         if(clsid != CLSID_OverlayMixer
    00628                         /*&& clsid != CLSID_OverlayMixer2*/
    00629                         && clsid != CLSID_VideoMixingRenderer
    00630                         && clsid != CLSID_VideoMixingRenderer9
    00631                         && clsid != __uuidof(ffdshow)
    00632                         && (clsid != __uuidof(dvs) || ver < 0x0234)
    00633                         && (clsid != __uuidof(dvsauto) || ver < 0x0234)
    00634                         && clsid != __uuidof(dladapter))
    00635                                 return E_FAIL;
    00636                 }
    00637         }
    00638
    00639         return __super::CheckConnect(dir, pPin);
    00640 }
    00641
    00642 HRESULT CMpeg2DecFilter::CheckInputType(const CMediaType* mtIn)
    00643 {
    00644         if(mtIn->formattype == FORMAT_MPEG2_VIDEO && mtIn->pbFormat)
    00645         {
    00646                 MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mtIn->pbFormat;
    00647                 if(vih->cbSequenceHeader > 0 && (vih->dwSequenceHeader[0] & 0x00ffffff) != 0x00010000)
    00648                         return VFW_E_TYPE_NOT_ACCEPTED;
    00649         }
    00650
    00651         return (mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
    00652                         || mtIn->majortype == MEDIATYPE_MPEG2_PACK && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
    00653                         || mtIn->majortype == MEDIATYPE_MPEG2_PES && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
    00654                         || mtIn->majortype == MEDIATYPE_Video && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
    00655                         || mtIn->majortype == MEDIATYPE_Video && mtIn->subtype == MEDIASUBTYPE_MPEG1Packet
    00656                         || mtIn->majortype == MEDIATYPE_Video && mtIn->subtype == MEDIASUBTYPE_MPEG1Payload)
    00657                 ? S_OK
    00658                 : VFW_E_TYPE_NOT_ACCEPTED;
    00659 }
    00660
    00661 HRESULT CMpeg2DecFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
    00662 {
    00663         bool fPlanarYUV = mtOut->subtype == MEDIASUBTYPE_YV12 || mtOut->subtype == MEDIASUBTYPE_I420 || mtOut->subtype == MEDIASUBTYPE_IYUV;
    00664
    00665         return SUCCEEDED(__super::CheckTransform(mtIn, mtOut))
    00666                 && (!fPlanarYUV || IsPlanarYUVEnabled())
    00667                 ? S_OK
    00668                 : VFW_E_TYPE_NOT_ACCEPTED;
    00669 }
    00670
    00671 HRESULT CMpeg2DecFilter::StartStreaming()
    00672 {
    00673         HRESULT hr = __super::StartStreaming();
    00674         if(FAILED(hr)) return hr;
    00675
    00676         m_dec.Attach(new CMpeg2Dec());
    00677         if(!m_dec) return E_OUTOFMEMORY;
    00678
    00679         InputTypeChanged();
    00680
    00681         return S_OK;
    00682 }
    00683
    00684 HRESULT CMpeg2DecFilter::StopStreaming()
    00685 {
    00686         m_dec.Free();
    00687
    00688         return __super::StopStreaming();
    00689 }
    00690
    00691 HRESULT CMpeg2DecFilter::AlterQuality(Quality q)
    00692 {
    00693         if(q.Late > 500*10000i64) m_fDropFrames = true;
    00694         else if(q.Late <= 0) m_fDropFrames = false;
    00695
    00696 //      TRACE(_T("CMpeg2DecFilter::AlterQuality: Type=%d, Proportion=%d, Late=%I64d, TimeStamp=%I64d\n"), q.Type, q.Proportion, q.Late, q.TimeStamp);
    00697         return S_OK;
    00698 }
    00699
    00700 // IMpeg2DecFilter
    00701
    00702 STDMETHODIMP CMpeg2DecFilter::SetDeinterlaceMethod(ditype di)
    00703 {
    00704         CAutoLock cAutoLock(&m_csProps);
    00705         m_di = di;
    00706         return S_OK;
    00707 }
    00708
    00709 STDMETHODIMP_(ditype) CMpeg2DecFilter::GetDeinterlaceMethod()
    00710 {
    00711         CAutoLock cAutoLock(&m_csProps);
    00712         return m_di;
    00713 }
    00714
    00715 void CMpeg2DecFilter::CalcBrCont(BYTE* YTbl, double bright, double cont)
    00716 {
    00717         int Cont = (int)(cont * 512);
    00718         int Bright = (int)bright;
    00719
    00720         for(int i = 0; i < 256; i++)
    00721         {
    00722                 int y = ((Cont * (i - 16)) >> 9) + Bright + 16;
    00723                 YTbl[i] = min(max(y, 0), 255);
    00724 //              YTbl[i] = min(max(y, 16), 235);
    00725         }
    00726 }
    00727
    00728 void CMpeg2DecFilter::CalcHueSat(BYTE* UTbl, BYTE* VTbl, double hue, double sat)
    00729 {
    00730         int Sat = (int)(sat * 512);
    00731         double Hue = (hue * 3.1415926) / 180.0;
    00732         int Sin = (int)(sin(Hue) * 4096);
    00733         int Cos = (int)(cos(Hue) * 4096);
    00734
    00735         for(int y = 0; y < 256; y++)
    00736         {
    00737                 for(int x = 0; x < 256; x++)
    00738                 {
    00739                         int u = x - 128;
    00740                         int v = y - 128;
    00741                         int ux = (u * Cos + v * Sin) >> 12;
    00742                         v = (v * Cos - u * Sin) >> 12;
    00743                         u = ((ux * Sat) >> 9) + 128;
    00744                         v = ((v * Sat) >> 9) + 128;
    00745                         u = min(max(u, 16), 235);
    00746                         v = min(max(v, 16), 235);
    00747                         UTbl[(y << 8) | x] = u;
    00748                         VTbl[(y << 8) | x] = v;
    00749                 }
    00750         }
    00751 }
    00752
    00753 void CMpeg2DecFilter::ApplyBrContHueSat(BYTE* srcy, BYTE* srcu, BYTE* srcv, int w, int h, int pitch)
    00754 {
    00755         CAutoLock cAutoLock(&m_csProps);
    00756
    00757         double EPSILON = 1e-4;
    00758
    00759         if(fabs(m_bright-0.0) > EPSILON || fabs(m_cont-1.0) > EPSILON)
    00760         {
    00761                 for(int size = pitch*h; size > 0; size--)
    00762                 {
    00763                         *srcy++ = m_YTbl[*srcy];
    00764                 }
    00765         }
    00766
    00767         pitch /= 2;
    00768         w /= 2;
    00769         h /= 2;
    00770
    00771         if(fabs(m_hue-0.0) > EPSILON || fabs(m_sat-1.0) > EPSILON)
    00772         {
    00773                 for(int size = pitch*h; size > 0; size--)
    00774                 {
    00775                         WORD uv = (*srcv<<8)|*srcu;
    00776                         *srcu++ = m_UTbl[uv];
    00777                         *srcv++ = m_VTbl[uv];
    00778                 }
    00779         }
    00780 }
    00781
    00782 STDMETHODIMP CMpeg2DecFilter::SetBrightness(double bright)
    00783 {
    00784         CAutoLock cAutoLock(&m_csProps);
    00785         CalcBrCont(m_YTbl, m_bright = bright, m_cont);
    00786         return S_OK;
    00787 }
    00788
    00789 STDMETHODIMP CMpeg2DecFilter::SetContrast(double cont)
    00790 {
    00791         CAutoLock cAutoLock(&m_csProps);
    00792         CalcBrCont(m_YTbl, m_bright, m_cont = cont);
    00793         return S_OK;
    00794 }
    00795
    00796 STDMETHODIMP CMpeg2DecFilter::SetHue(double hue)
    00797 {
    00798         CAutoLock cAutoLock(&m_csProps);
    00799         CalcHueSat(m_UTbl, m_VTbl, m_hue = hue, m_sat);
    00800         return S_OK;
    00801 }
    00802
    00803 STDMETHODIMP CMpeg2DecFilter::SetSaturation(double sat)
    00804 {
    00805         CAutoLock cAutoLock(&m_csProps);
    00806         CalcHueSat(m_UTbl, m_VTbl, m_hue, m_sat = sat);
    00807         return S_OK;
    00808 }
    00809
    00810 STDMETHODIMP_(double) CMpeg2DecFilter::GetBrightness()
    00811 {
    00812         CAutoLock cAutoLock(&m_csProps);
    00813         return m_bright;
    00814 }
    00815
    00816 STDMETHODIMP_(double) CMpeg2DecFilter::GetContrast()
    00817 {
    00818         CAutoLock cAutoLock(&m_csProps);
    00819         return m_cont;
    00820 }
    00821
    00822 STDMETHODIMP_(double) CMpeg2DecFilter::GetHue()
    00823 {
    00824         CAutoLock cAutoLock(&m_csProps);
    00825         return m_hue;
    00826 }
    00827
    00828 STDMETHODIMP_(double) CMpeg2DecFilter::GetSaturation()
    00829 {
    00830         CAutoLock cAutoLock(&m_csProps);
    00831         return m_sat;
    00832 }
    00833
    00834 STDMETHODIMP CMpeg2DecFilter::EnableForcedSubtitles(bool fEnable)
    00835 {
    00836         CAutoLock cAutoLock(&m_csProps);
    00837         m_fForcedSubs = fEnable;
    00838         return S_OK;
    00839 }
    00840
    00841 STDMETHODIMP_(bool) CMpeg2DecFilter::IsForcedSubtitlesEnabled()
    00842 {
    00843         CAutoLock cAutoLock(&m_csProps);
    00844         return m_fForcedSubs;
    00845 }
    00846
    00847 STDMETHODIMP CMpeg2DecFilter::EnablePlanarYUV(bool fEnable)
    00848 {
    00849         CAutoLock cAutoLock(&m_csProps);
    00850         m_fPlanarYUV = fEnable;
    00851         return S_OK;
    00852 }
    00853
    00854 STDMETHODIMP_(bool) CMpeg2DecFilter::IsPlanarYUVEnabled()
    00855 {
    00856         CAutoLock cAutoLock(&m_csProps);
    00857         return m_fPlanarYUV;
    00858 }
    00859
    00860 //
    00861 // CMpeg2DecInputPin
    00862 //
    00863
    00864 CMpeg2DecInputPin::CMpeg2DecInputPin(CTransformFilter* pFilter, HRESULT* phr, LPWSTR pName)
    00865         : CDeCSSInputPin(NAME("CMpeg2DecInputPin"), pFilter, phr, pName)
    00866 {
    00867         m_CorrectTS = 0;
    00868         m_ratechange.Rate = 10000;
    00869         m_ratechange.StartTime = _I64_MAX;
    00870 }
    00871
    00872 // IKsPropertySet
    00873
    00874 STDMETHODIMP CMpeg2DecInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength)
    00875 {
    00876         if(PropSet != AM_KSPROPSETID_TSRateChange /*&& PropSet != AM_KSPROPSETID_DVD_RateChange*/)
    00877                 return __super::Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength);
    00878
    00879         if(PropSet == AM_KSPROPSETID_TSRateChange)
    00880         switch(Id)
    00881         {
    00882         case AM_RATE_SimpleRateChange:
    00883                 {
    00884                         AM_SimpleRateChange* p = (AM_SimpleRateChange*)pPropertyData;
    00885                         if(!m_CorrectTS) return E_PROP_ID_UNSUPPORTED;
    00886                         CAutoLock cAutoLock(&m_csRateLock);
    00887                         m_ratechange = *p;
    00888                         DbgLog((LOG_TRACE, 0, _T("StartTime=%I64d, Rate=%d"), p->StartTime, p->Rate));
    00889                 }
    00890                 break;
    00891         case AM_RATE_UseRateVersion:
    00892                 {
    00893                         WORD* p = (WORD*)pPropertyData;
    00894                         if(*p > 0x0101) return E_PROP_ID_UNSUPPORTED;
    00895                 }
    00896                 break;
    00897         case AM_RATE_CorrectTS:
    00898                 {
    00899                         LONG* p = (LONG*)pPropertyData;
    00900                         m_CorrectTS = *p;
    00901                 }
    00902                 break;
    00903         default:
    00904                 return E_PROP_ID_UNSUPPORTED;
    00905         }
    00906 /*
    00907         if(PropSet == AM_KSPROPSETID_DVD_RateChange)
    00908         switch(Id)
    00909         {
    00910         case AM_RATE_ChangeRate:
    00911                 {
    00912                         AM_DVD_ChangeRate* p = (AM_DVD_ChangeRate*)pPropertyData;
    00913                 }
    00914                 break;
    00915         default:
    00916                 return E_PROP_ID_UNSUPPORTED;
    00917         }
    00918 */
    00919         return S_OK;
    00920 }
    00921
    00922 STDMETHODIMP CMpeg2DecInputPin::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned)
    00923 {
    00924         if(PropSet != AM_KSPROPSETID_TSRateChange /*&& PropSet != AM_KSPROPSETID_DVD_RateChange*/)
    00925                 return __super::Get(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength, pBytesReturned);
    00926
    00927         if(PropSet == AM_KSPROPSETID_TSRateChange)
    00928         switch(Id)
    00929         {
    00930         case AM_RATE_SimpleRateChange:
    00931                 {
    00932                         AM_SimpleRateChange* p = (AM_SimpleRateChange*)pPropertyData;
    00933                         return E_PROP_ID_UNSUPPORTED;
    00934                 }
    00935                 break;
    00936         case AM_RATE_MaxFullDataRate:
    00937                 {
    00938                         AM_MaxFullDataRate* p = (AM_MaxFullDataRate*)pPropertyData;
    00939                         *p = 8*10000;
    00940                         *pBytesReturned = sizeof(AM_MaxFullDataRate);
    00941                 }
    00942                 break;
    00943         case AM_RATE_QueryFullFrameRate:
    00944                 {
    00945                         AM_QueryRate* p = (AM_QueryRate*)pPropertyData;
    00946                         p->lMaxForwardFullFrame = 8*10000;
    00947                         p->lMaxReverseFullFrame = 8*10000;
    00948                         *pBytesReturned = sizeof(AM_QueryRate);
    00949                 }
    00950                 break;
    00951         case AM_RATE_QueryLastRateSegPTS:
    00952                 {
    00953                         REFERENCE_TIME* p = (REFERENCE_TIME*)pPropertyData;
    00954                         return E_PROP_ID_UNSUPPORTED;
    00955                 }
    00956                 break;
    00957         default:
    00958                 return E_PROP_ID_UNSUPPORTED;
    00959         }
    00960 /*
    00961         if(PropSet == AM_KSPROPSETID_DVD_RateChange)
    00962         switch(Id)
    00963         {
    00964         case AM_RATE_FullDataRateMax:
    00965                 {
    00966                         AM_MaxFullDataRate* p = (AM_MaxFullDataRate*)pPropertyData;
    00967                 }
    00968                 break;
    00969         case AM_RATE_ReverseDecode:
    00970                 {
    00971                         LONG* p = (LONG*)pPropertyData;
    00972                 }
    00973                 break;
    00974         case AM_RATE_DecoderPosition:
    00975                 {
    00976                         AM_DVD_DecoderPosition* p = (AM_DVD_DecoderPosition*)pPropertyData;
    00977                 }
    00978                 break;
    00979         case AM_RATE_DecoderVersion:
    00980                 {
    00981                         LONG* p = (LONG*)pPropertyData;
    00982                 }
    00983                 break;
    00984         default:
    00985                 return E_PROP_ID_UNSUPPORTED;
    00986         }
    00987 */
    00988         return S_OK;
    00989 }
    00990
    00991 STDMETHODIMP CMpeg2DecInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport)
    00992 {
    00993         if(PropSet != AM_KSPROPSETID_TSRateChange /*&& PropSet != AM_KSPROPSETID_DVD_RateChange*/)
    00994                 return __super::QuerySupported(PropSet, Id, pTypeSupport);
    00995
    00996         if(PropSet == AM_KSPROPSETID_TSRateChange)
    00997         switch(Id)
    00998         {
    00999         case AM_RATE_SimpleRateChange:
    01000                 *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
    01001                 break;
    01002         case AM_RATE_MaxFullDataRate:
    01003                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    01004                 break;
    01005         case AM_RATE_UseRateVersion:
    01006                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    01007                 break;
    01008         case AM_RATE_QueryFullFrameRate:
    01009                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    01010                 break;
    01011         case AM_RATE_QueryLastRateSegPTS:
    01012                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    01013                 break;
    01014         case AM_RATE_CorrectTS:
    01015                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    01016                 break;
    01017         default:
    01018                 return E_PROP_ID_UNSUPPORTED;
    01019         }
    01020 /*
    01021         if(PropSet == AM_KSPROPSETID_DVD_RateChange)
    01022         switch(Id)
    01023         {
    01024         case AM_RATE_ChangeRate:
    01025                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    01026                 break;
    01027         case AM_RATE_FullDataRateMax:
    01028                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    01029                 break;
    01030         case AM_RATE_ReverseDecode:
    01031                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    01032                 break;
    01033         case AM_RATE_DecoderPosition:
    01034                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    01035                 break;
    01036         case AM_RATE_DecoderVersion:
    01037                 *pTypeSupport = KSPROPERTY_SUPPORT_GET;
    01038                 break;
    01039         default:
    01040                 return E_PROP_ID_UNSUPPORTED;
    01041         }
    01042 */
    01043         return S_OK;
    01044 }
    01045
    01046 //
    01047 // CSubpicInputPin
    01048 //
    01049
    01050 #define PTS2RT(pts) (10000i64*pts/90)
    01051
    01052 CSubpicInputPin::CSubpicInputPin(CTransformFilter* pFilter, HRESULT* phr)
    01053         : CMpeg2DecInputPin(pFilter, phr, L"SubPicture")
    01054         , m_spon(TRUE)
    01055         , m_fsppal(false)
    01056 {
    01057         m_sppal[0].Y = 0x00;
    01058         m_sppal[0].U = m_sppal[0].V = 0x80;
    01059         m_sppal[1].Y = 0xe0;
    01060         m_sppal[1].U = m_sppal[1].V = 0x80;
    01061         m_sppal[2].Y = 0x80;
    01062         m_sppal[2].U = m_sppal[2].V = 0x80;
    01063         m_sppal[3].Y = 0x20;
    01064         m_sppal[3].U = m_sppal[3].V = 0x80;
    01065 }
    01066
    01067 HRESULT CSubpicInputPin::CheckMediaType(const CMediaType* mtIn)
    01068 {
    01069         return (mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK
    01070                         || mtIn->majortype == MEDIATYPE_MPEG2_PACK
    01071                         || mtIn->majortype == MEDIATYPE_MPEG2_PES
    01072                         || mtIn->majortype == MEDIATYPE_Video)
    01073                 && (mtIn->subtype == MEDIASUBTYPE_DVD_SUBPICTURE
    01074                         || mtIn->subtype == MEDIASUBTYPE_CVD_SUBPICTURE
    01075                         || mtIn->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE)
    01076                 ? S_OK
    01077                 : VFW_E_TYPE_NOT_ACCEPTED;
    01078 }
    01079
    01080 HRESULT CSubpicInputPin::SetMediaType(const CMediaType* mtIn)
    01081 {
    01082         return CBasePin::SetMediaType(mtIn);
    01083 }
    01084
    01085 bool CSubpicInputPin::HasAnythingToRender(REFERENCE_TIME rt)
    01086 {
    01087         if(!IsConnected()) return(false);
    01088
    01089         CAutoLock cAutoLock(&m_csReceive);
    01090
    01091         POSITION pos = m_sps.GetHeadPosition();
    01092         while(pos)
    01093         {
    01094                 spu* sp = m_sps.GetNext(pos);
    01095                 if(sp->m_rtStart <= rt && rt < sp->m_rtStop && (/*sp->m_psphli ||*/ sp->m_fForced || m_spon))
    01096                         return(true);
    01097         }
    01098
    01099         return(false);
    01100 }
    01101
    01102 void CSubpicInputPin::RenderSubpics(REFERENCE_TIME rt, BYTE** yuv, int w, int h)
    01103 {
    01104         CAutoLock cAutoLock(&m_csReceive);
    01105
    01106         POSITION pos;
    01107
    01108         // remove no longer needed things first
    01109         pos = m_sps.GetHeadPosition();
    01110         while(pos)
    01111         {
    01112                 POSITION cur = pos;
    01113                 spu* sp = m_sps.GetNext(pos);
    01114                 if(sp->m_rtStop <= rt) m_sps.RemoveAt(cur);
    01115         }
    01116
    01117         pos = m_sps.GetHeadPosition();
    01118         while(pos)
    01119         {
    01120                 spu* sp = m_sps.GetNext(pos);
    01121                 if(sp->m_rtStart <= rt && rt < sp->m_rtStop
    01122                 && (m_spon || sp->m_fForced && (((CMpeg2DecFilter*)m_pFilter)->IsForcedSubtitlesEnabled() || sp->m_psphli)))
    01123                         sp->Render(yuv, w, h, m_sppal, m_fsppal);
    01124         }
    01125 }
    01126
    01127 HRESULT CSubpicInputPin::Transform(IMediaSample* pSample)
    01128 {
    01129         HRESULT hr;
    01130
    01131         AM_MEDIA_TYPE* pmt;
    01132         if(SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt)
    01133         {
    01134                 CMediaType mt(*pmt);
    01135                 SetMediaType(&mt);
    01136                 DeleteMediaType(pmt);
    01137         }
    01138
    01139         BYTE* pDataIn = NULL;
    01140         if(FAILED(hr = pSample->GetPointer(&pDataIn))) return hr;
    01141
    01142         long len = pSample->GetActualDataLength();
    01143
    01144         StripPacket(pDataIn, len);
    01145
    01146         if(len <= 0) return S_FALSE;
    01147
    01148         if(m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE)
    01149         {
    01150                 pDataIn += 4;
    01151                 len -= 4;
    01152         }
    01153
    01154         if(len <= 0) return S_FALSE;
    01155
    01156         CAutoLock cAutoLock(&m_csReceive);
    01157
    01158         REFERENCE_TIME rtStart = 0, rtStop = 0;
    01159         hr = pSample->GetTime(&rtStart, &rtStop);
    01160
    01161         bool fRefresh = false;
    01162
    01163         if(FAILED(hr))
    01164         {
    01165                 if(!m_sps.IsEmpty())
    01166                 {
    01167                         spu* sp = m_sps.GetTail();
    01168                         sp->m_pData.SetSize(sp->m_pData.GetSize() + len);
    01169                         memcpy(sp->m_pData.GetData() + sp->m_pData.GetSize() - len, pDataIn, len);
    01170                 }
    01171         }
    01172         else
    01173         {
    01174                 POSITION pos = m_sps.GetTailPosition();
    01175                 while(pos)
    01176                 {
    01177                         POSITION cur = pos;
    01178                         spu* sp = m_sps.GetPrev(pos);
    01179                         if(sp->m_rtStop == _I64_MAX)
    01180                         {
    01181                                 sp->m_rtStop = rtStart;
    01182                                 break;
    01183                         }
    01184                 }
    01185
    01186                 CAutoPtr<spu> p;
    01187
    01188                 if(m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE) p.Attach(new dvdspu());
    01189                 else if(m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE) p.Attach(new cvdspu());
    01190                 else if(m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE) p.Attach(new svcdspu());
    01191                 else return E_FAIL;
    01192
    01193                 p->m_rtStart = rtStart;
    01194                 p->m_rtStop = _I64_MAX;
    01195
    01196                 p->m_pData.SetSize(len);
    01197                 memcpy(p->m_pData.GetData(), pDataIn, len);
    01198
    01199                 if(m_sphli && p->m_rtStart == PTS2RT(m_sphli->StartPTM))
    01200                 {
    01201                         p->m_psphli = m_sphli;
    01202                         fRefresh = true;
    01203                 }
    01204
    01205                 m_sps.AddTail(p);
    01206         }
    01207
    01208         if(!m_sps.IsEmpty())
    01209         {
    01210                 m_sps.GetTail()->Parse();
    01211         }
    01212
    01213         if(fRefresh)
    01214         {
    01215 //              ((CMpeg2DecFilter*)m_pFilter)->Deliver(true);
    01216         }
    01217
    01218         return S_FALSE;
    01219 }
    01220
    01221 STDMETHODIMP CSubpicInputPin::EndFlush()
    01222 {
    01223         CAutoLock cAutoLock(&m_csReceive);
    01224         m_sps.RemoveAll();
    01225         return S_OK;
    01226 }
    01227
    01228 // IKsPropertySet
    01229
    01230 STDMETHODIMP CSubpicInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength)
    01231 {
    01232         if(PropSet != AM_KSPROPSETID_DvdSubPic)
    01233                 return __super::Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength);
    01234
    01235         bool fRefresh = false;
    01236
    01237         switch(Id)
    01238         {
    01239         case AM_PROPERTY_DVDSUBPIC_PALETTE:
    01240                 {
    01241                         CAutoLock cAutoLock(&m_csReceive);
    01242                         AM_PROPERTY_SPPAL* pSPPAL = (AM_PROPERTY_SPPAL*)pPropertyData;
    01243                         memcpy(m_sppal, pSPPAL->sppal, sizeof(AM_PROPERTY_SPPAL));
    01244                         m_fsppal = true;
    01245
    01246                         DbgLog((LOG_TRACE, 0, _T("new palette")));
    01247                 }
    01248                 break;
    01249         case AM_PROPERTY_DVDSUBPIC_HLI:
    01250                 {
    01251                         CAutoLock cAutoLock(&m_csReceive);
    01252
    01253                         AM_PROPERTY_SPHLI* pSPHLI = (AM_PROPERTY_SPHLI*)pPropertyData;
    01254
    01255                         m_sphli.Free();
    01256
    01257                         if(pSPHLI->HLISS)
    01258                         {
    01259                                 POSITION pos = m_sps.GetHeadPosition();
    01260                                 while(pos)
    01261                                 {
    01262                                         spu* sp = m_sps.GetNext(pos);
    01263                                         if(sp->m_rtStart <= PTS2RT(pSPHLI->StartPTM) && PTS2RT(pSPHLI->StartPTM) < sp->m_rtStop)
    01264                                         {
    01265                                                 fRefresh = true;
    01266                                                 sp->m_psphli.Free();
    01267                                                 sp->m_psphli.Attach(new AM_PROPERTY_SPHLI());
    01268                                                 memcpy((AM_PROPERTY_SPHLI*)sp->m_psphli, pSPHLI, sizeof(AM_PROPERTY_SPHLI));
    01269                                         }
    01270                                 }
    01271
    01272                                 if(!fRefresh) // save it for later, a subpic might be late for this hli
    01273                                 {
    01274                                         m_sphli.Attach(new AM_PROPERTY_SPHLI());
    01275                                         memcpy((AM_PROPERTY_SPHLI*)m_sphli, pSPHLI, sizeof(AM_PROPERTY_SPHLI));
    01276                                 }
    01277                         }
    01278                         else
    01279                         {
    01280                                 POSITION pos = m_sps.GetHeadPosition();
    01281                                 while(pos)
    01282                                 {
    01283                                         spu* sp = m_sps.GetNext(pos);
    01284                                         fRefresh |= !!sp->m_psphli;
    01285                                         sp->m_psphli.Free();
    01286                                 }
    01287                         }
    01288
    01289                         if(pSPHLI->HLISS)
    01290                         DbgLog((LOG_TRACE, 0, _T("hli: %I64d - %I64d, (%d,%d) - (%d,%d)"),
    01291                                 PTS2RT(pSPHLI->StartPTM)/10000, PTS2RT(pSPHLI->EndPTM)/10000,
    01292                                 pSPHLI->StartX, pSPHLI->StartY, pSPHLI->StopX, pSPHLI->StopY));
    01293                 }
    01294                 break;
    01295         case AM_PROPERTY_DVDSUBPIC_COMPOSIT_ON:
    01296                 {
    01297                         CAutoLock cAutoLock(&m_csReceive);
    01298                         AM_PROPERTY_COMPOSIT_ON* pCompositOn = (AM_PROPERTY_COMPOSIT_ON*)pPropertyData;
    01299                         m_spon = *pCompositOn;
    01300                 }
    01301                 break;
    01302         default:
    01303                 return E_PROP_ID_UNSUPPORTED;
    01304         }
    01305
    01306         if(fRefresh)
    01307         {
    01308                 ((CMpeg2DecFilter*)m_pFilter)->Deliver(true);
    01309         }
    01310
    01311         return S_OK;
    01312 }
    01313
    01314 STDMETHODIMP CSubpicInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport)
    01315 {
    01316         if(PropSet != AM_KSPROPSETID_DvdSubPic)
    01317                 return __super::QuerySupported(PropSet, Id, pTypeSupport);
    01318
    01319         switch(Id)
    01320         {
    01321         case AM_PROPERTY_DVDSUBPIC_PALETTE:
    01322                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    01323                 break;
    01324         case AM_PROPERTY_DVDSUBPIC_HLI:
    01325                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    01326                 break;
    01327         case AM_PROPERTY_DVDSUBPIC_COMPOSIT_ON:
    01328                 *pTypeSupport = KSPROPERTY_SUPPORT_SET;
    01329                 break;
    01330         default:
    01331                 return E_PROP_ID_UNSUPPORTED;
    01332         }
    01333
    01334         return S_OK;
    01335 }
    01336
    01337 // CSubpicInputPin::spu
    01338
    01339 static __inline BYTE GetNibble(BYTE* p, DWORD* offset, int& nField, int& fAligned)
    01340 {
    01341         BYTE ret = (p[offset[nField]] >> (fAligned << 2)) & 0x0f;
    01342         offset[nField] += 1-fAligned;
    01343         fAligned = !fAligned;
    01344     return ret;
    01345 }
    01346
    01347 static __inline BYTE GetHalfNibble(BYTE* p, DWORD* offset, int& nField, int& n)
    01348 {
    01349         BYTE ret = (p[offset[nField]] >> (n << 1)) & 0x03;
    01350         if(!n) offset[nField]++;
    01351         n = (n-1+4)&3;
    01352     return ret;
    01353 }
    01354
    01355 static __inline void DrawPixel(BYTE** yuv, CPoint pt, int pitch, AM_DVD_YUV& c)
    01356 {
    01357         if(c.Reserved == 0) return;
    01358
    01359         BYTE* p = &yuv[0][pt.y*pitch + pt.x];
    01360 //      *p = (*p*(15-contrast) + sppal[color].Y*contrast)>>4;
    01361         *p -= (*p - c.Y) * c.Reserved >> 4;
    01362
    01363         if(pt.y&1) return; // since U/V is half res there is no need to overwrite the same line again
    01364
    01365         pt.x = (pt.x + 1) / 2;
    01366         pt.y = (pt.y /*+ 1*/) / 2; // only paint the upper field always, don't round it
    01367         pitch /= 2;
    01368
    01369         // U/V is exchanged? wierd but looks true when comparing the outputted colors from other decoders
    01370
    01371         p = &yuv[1][pt.y*pitch + pt.x];
    01372 //      *p = (BYTE)(((((int)*p-0x80)*(15-contrast) + ((int)sppal[color].V-0x80)*contrast) >> 4) + 0x80);
    01373         *p -= (*p - c.V) * c.Reserved >> 4;
    01374
    01375         p = &yuv[2][pt.y*pitch + pt.x];
    01376 //      *p = (BYTE)(((((int)*p-0x80)*(15-contrast) + ((int)sppal[color].U-0x80)*contrast) >> 4) + 0x80);
    01377         *p -= (*p - c.U) * c.Reserved >> 4;
    01378
    01379         // Neighter of the blending formulas are accurate (">>4" should be "/15").
    01380         // Even though the second one is a bit worse, since we are scaling the difference only,
    01381         // the error is still not noticable.
    01382 }
    01383
    01384 static __inline void DrawPixels(BYTE** yuv, int pitch, CPoint pt, int len, AM_DVD_YUV& c, CRect& rc)
    01385 {
    01386     if(pt.y < rc.top || pt.y >= rc.bottom) return;
    01387         if(pt.x < rc.left) {len -= rc.left - pt.x; pt.x = rc.left;}
    01388         if(pt.x + len > rc.right) len = rc.right - pt.x;
    01389         if(len <= 0 || pt.x >= rc.right) return;
    01390
    01391         if(c.Reserved == 0)
    01392         {
    01393                 if(rc.IsRectEmpty())
    01394                         return;
    01395
    01396                 if(pt.y < rc.top || pt.y >= rc.bottom
    01397                 || pt.x+len < rc.left || pt.x >= rc.right)
    01398                         return;
    01399         }
    01400
    01401         while(len-- > 0)
    01402         {
    01403                 DrawPixel(yuv, pt, pitch, c);
    01404                 pt.x++;
    01405         }
    01406 }
    01407
    01408 // CSubpicInputPin::dvdspu
    01409
    01410 bool CSubpicInputPin::dvdspu::Parse()
    01411 {
    01412         BYTE* p = m_pData.GetData();
    01413
    01414         WORD packetsize = (p[0]<<8)|p[1];
    01415         WORD datasize = (p[2]<<8)|p[3];
    01416
    01417     if(packetsize > m_pData.GetSize() || datasize > packetsize)
    01418                 return(false);
    01419
    01420         int i, next = datasize;
    01421
    01422         #define GetWORD (p[i]<<8)|p[i+1]; i += 2
    01423
    01424         do
    01425         {
    01426                 i = next;
    01427
    01428                 int pts = GetWORD;
    01429                 next = GetWORD;
    01430
    01431                 if(next > packetsize || next < datasize)
    01432                         return(false);
    01433
    01434                 for(bool fBreak = false; !fBreak; )
    01435                 {
    01436                         int len = 0;
    01437
    01438                         switch(p[i])
    01439                         {
    01440                                 case 0x00: len = 0; break;
    01441                                 case 0x01: len = 0; break;
    01442                                 case 0x02: len = 0; break;
    01443                                 case 0x03: len = 2; break;
    01444                                 case 0x04: len = 2; break;
    01445                                 case 0x05: len = 6; break;
    01446                                 case 0x06: len = 4; break;
    01447                                 default: len = 0; break;
    01448                         }
    01449
    01450                         if(i+len >= packetsize)
    01451                         {
    01452                                 TRACE(_T("Warning: Wrong subpicture parameter block ending\n"));
    01453                                 break;
    01454                         }
    01455
    01456                         switch(p[i++])
    01457                         {
    01458                                 case 0x00: // forced start displaying
    01459                                         m_fForced = true;
    01460                                         break;
    01461                                 case 0x01: // normal start displaying
    01462                                         m_fForced = false;
    01463                                         break;
    01464                                 case 0x02: // stop displaying
    01465                                         m_rtStop = m_rtStart + 1024*PTS2RT(pts);
    01466                                         break;
    01467                                 case 0x03:
    01468                                         m_sphli.ColCon.emph2col = p[i]>>4;
    01469                                         m_sphli.ColCon.emph1col = p[i]&0xf;
    01470                                         m_sphli.ColCon.patcol = p[i+1]>>4;
    01471                                         m_sphli.ColCon.backcol = p[i+1]&0xf;
    01472                                         i += 2;
    01473                                         break;
    01474                                 case 0x04:
    01475                                         m_sphli.ColCon.emph2con = p[i]>>4;
    01476                                         m_sphli.ColCon.emph1con = p[i]&0xf;
    01477                                         m_sphli.ColCon.patcon = p[i+1]>>4;
    01478                                         m_sphli.ColCon.backcon = p[i+1]&0xf;
    01479                                         i += 2;
    01480                                         break;
    01481                                 case 0x05:
    01482                                         m_sphli.StartX = (p[i]<<4) + (p[i+1]>>4);
    01483                                         m_sphli.StopX = ((p[i+1]&0x0f)<<8) + p[i+2]+1;
    01484                                         m_sphli.StartY = (p[i+3]<<4) + (p[i+4]>>4);
    01485                                         m_sphli.StopY = ((p[i+4]&0x0f)<<8) + p[i+5]+1;
    01486                                         i += 6;
    01487                                         break;
    01488                                 case 0x06:
    01489                                         m_offset[0] = GetWORD;
    01490                                         m_offset[1] = GetWORD;
    01491                                         break;
    01492                                 case 0xff: // end of ctrlblk
    01493                                         fBreak = true;
    01494                                         continue;
    01495                                 default: // skip this ctrlblk
    01496                                         fBreak = true;
    01497                                         break;
    01498                         }
    01499                 }
    01500         }
    01501         while(i <= next && i < packetsize);
    01502
    01503         return(true);
    01504 }
    01505
    01506 void CSubpicInputPin::dvdspu::Render(BYTE** yuv, int w, int h, AM_DVD_YUV* sppal, bool fsppal)
    01507 {
    01508         BYTE* p = m_pData.GetData();
    01509         DWORD offset[2] = {m_offset[0], m_offset[1]};
    01510
    01511         AM_PROPERTY_SPHLI sphli = m_sphli;
    01512         CPoint pt(sphli.StartX, sphli.StartY);
    01513         CRect rc(pt, CPoint(sphli.StopX, sphli.StopY));
    01514
    01515         CRect rcclip(0, 0, w, h);
    01516         rcclip &= rc;
    01517
    01518         if(m_psphli)
    01519         {
    01520                 rcclip &= CRect(m_psphli->StartX, m_psphli->StartY, m_psphli->StopX, m_psphli->StopY);
    01521                 sphli = *m_psphli;
    01522         }
    01523
    01524         AM_DVD_YUV pal[4];
    01525         pal[0] = sppal[fsppal ? sphli.ColCon.backcol : 0];
    01526         pal[0].Reserved = sphli.ColCon.backcon;
    01527         pal[1] = sppal[fsppal ? sphli.ColCon.patcol : 1];
    01528         pal[1].Reserved = sphli.ColCon.patcon;
    01529         pal[2] = sppal[fsppal ? sphli.ColCon.emph1col : 2];
    01530         pal[2].Reserved = sphli.ColCon.emph1con;
    01531         pal[3] = sppal[fsppal ? sphli.ColCon.emph2col : 3];
    01532         pal[3].Reserved = sphli.ColCon.emph2con;
    01533
    01534         int nField = 0;
    01535         int fAligned = 1;
    01536
    01537         DWORD end[2] = {offset[1], (p[2]<<8)|p[3]};
    01538
    01539         while((nField == 0 && offset[0] < end[0]) || (nField == 1 && offset[1] < end[1]))
    01540         {
    01541                 DWORD code;
    01542
    01543                 if((code = GetNibble(p, offset, nField, fAligned)) >= 0x4
    01544                 || (code = (code << 4) | GetNibble(p, offset, nField, fAligned)) >= 0x10
    01545                 || (code = (code << 4) | GetNibble(p, offset, nField, fAligned)) >= 0x40
    01546                 || (code = (code << 4) | GetNibble(p, offset, nField, fAligned)) >= 0x100)
    01547                 {
    01548                         DrawPixels(yuv, w, pt, code >> 2, pal[code&3], rcclip);
    01549                         if((pt.x += code >> 2) < rc.right) continue;
    01550                 }
    01551
    01552                 DrawPixels(yuv, w, pt, rc.right - pt.x, pal[code&3], rcclip);
    01553
    01554                 if(!fAligned) GetNibble(p, offset, nField, fAligned); // align to byte
    01555
    01556                 pt.x = rc.left;
    01557                 pt.y++;
    01558                 nField = 1 - nField;
    01559         }
    01560 }
    01561
    01562 // CSubpicInputPin::cvdspu
    01563
    01564 bool CSubpicInputPin::cvdspu::Parse()
    01565 {
    01566         BYTE* p = m_pData.GetData();
    01567
    01568         WORD packetsize = (p[0]<<8)|p[1];
    01569         WORD datasize = (p[2]<<8)|p[3];
    01570
    01571     if(packetsize > m_pData.GetSize() || datasize > packetsize)
    01572                 return(false);
    01573
    01574         p = m_pData.GetData() + datasize;
    01575
    01576         for(int i = datasize, j = packetsize-4; i <= j; i+=4, p+=4)
    01577         {
    01578                 switch(p[0])
    01579                 {
    01580                 case 0x0c:
    01581                         break;
    01582                 case 0x04:
    01583                         m_rtStop = m_rtStart + 10000i64*((p[1]<<16)|(p[2]<<8)|p[3])/90;
    01584                         break;
    01585                 case 0x17:
    01586                         m_sphli.StartX = ((p[1]&0x0f)<<6) + (p[2]>>2);
    01587                         m_sphli.StartY = ((p[2]&0x03)<<8) + p[3];
    01588                         break;
    01589                 case 0x1f:
    01590                         m_sphli.StopX = ((p[1]&0x0f)<<6) + (p[2]>>2);
    01591                         m_sphli.StopY = ((p[2]&0x03)<<8) + p[3];
    01592                         break;
    01593                 case 0x24: case 0x25: case 0x26: case 0x27:
    01594                         m_sppal[0][p[0]-0x24].Y = p[1];
    01595                         m_sppal[0][p[0]-0x24].U = p[2];
    01596                         m_sppal[0][p[0]-0x24].V = p[3];
    01597                         break;
    01598                 case 0x2c: case 0x2d: case 0x2e: case 0x2f:
    01599                         m_sppal[1][p[0]-0x2c].Y = p[1];
    01600                         m_sppal[1][p[0]-0x2c].U = p[2];
    01601                         m_sppal[1][p[0]-0x2c].V = p[3];
    01602                         break;
    01603                 case 0x37:
    01604                         m_sppal[0][3].Reserved = p[2]>>4;
    01605                         m_sppal[0][2].Reserved = p[2]&0xf;
    01606                         m_sppal[0][1].Reserved = p[3]>>4;
    01607                         m_sppal[0][0].Reserved = p[3]&0xf;
    01608                         break;
    01609                 case 0x3f:
    01610                         m_sppal[1][3].Reserved = p[2]>>4;
    01611                         m_sppal[1][2].Reserved = p[2]&0xf;
    01612                         m_sppal[1][1].Reserved = p[3]>>4;
    01613                         m_sppal[1][0].Reserved = p[3]&0xf;
    01614                         break;
    01615                 case 0x47:
    01616                         m_offset[0] = (p[2]<<8)|p[3];
    01617                         break;
    01618                 case 0x4f:
    01619                         m_offset[1] = (p[2]<<8)|p[3];
    01620                         break;
    01621                 default:
    01622                         break;
    01623                 }
    01624         }
    01625
    01626         return(true);
    01627 }
    01628
    01629 void CSubpicInputPin::cvdspu::Render(BYTE** yuv, int w, int h, AM_DVD_YUV* sppal, bool fsppal)
    01630 {
    01631         BYTE* p = m_pData.GetData();
    01632         DWORD offset[2] = {m_offset[0], m_offset[1]};
    01633
    01634         CRect rcclip(0, 0, w, h);
    01635
    01636         /* FIXME: startx/y looks to be wrong in the sample I tested
    01637         CPoint pt(m_sphli.StartX, m_sphli.StartY);
    01638         CRect rc(pt, CPoint(m_sphli.StopX, m_sphli.StopY));
    01639         */
    01640
    01641         CSize size(m_sphli.StopX - m_sphli.StartX, m_sphli.StopY - m_sphli.StartY);
    01642         CPoint pt((rcclip.Width() - size.cx) / 2, (rcclip.Height()*3 - size.cy*1) / 4);
    01643         CRect rc(pt, size);
    01644
    01645         int nField = 0;
    01646         int fAligned = 1;
    01647
    01648         DWORD end[2] = {offset[1], (p[2]<<8)|p[3]};
    01649
    01650         while((nField == 0 && offset[0] < end[0]) || (nField == 1 && offset[1] < end[1]))
    01651         {
    01652                 BYTE code;
    01653
    01654                 if((code = GetNibble(p, offset, nField, fAligned)) >= 0x4)
    01655                 {
    01656                         DrawPixels(yuv, w, pt, code >> 2, m_sppal[0][code&3], rcclip);
    01657                         pt.x += code >> 2;
    01658                         continue;
    01659                 }
    01660
    01661                 code = GetNibble(p, offset, nField, fAligned);
    01662                 DrawPixels(yuv, w, pt, rc.right - pt.x, m_sppal[0][code&3], rcclip);
    01663
    01664                 if(!fAligned) GetNibble(p, offset, nField, fAligned); // align to byte
    01665
    01666                 pt.x = rc.left;
    01667                 pt.y++;
    01668                 nField = 1 - nField;
    01669         }
    01670 }
    01671
    01672 // CSubpicInputPin::svcdspu
    01673
    01674 bool CSubpicInputPin::svcdspu::Parse()
    01675 {
    01676         BYTE* p = m_pData.GetData();
    01677         BYTE* p0 = p;
    01678
    01679         if(m_pData.GetSize() < 2)
    01680                 return(false);
    01681
    01682         WORD packetsize = (p[0]<<8)|p[1]; p += 2;
    01683
    01684     if(packetsize > m_pData.GetSize())
    01685                 return(false);
    01686
    01687         bool duration = !!(*p++&0x04);
    01688
    01689         *p++; // unknown
    01690
    01691         if(duration)
    01692         {
    01693                 m_rtStop = m_rtStart + 10000i64*((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3])/90;
    01694                 p += 4;
    01695         }
    01696
    01697         m_sphli.StartX = m_sphli.StopX = (p[0]<<8)|p[1]; p += 2;
    01698         m_sphli.StartY = m_sphli.StopY = (p[0]<<8)|p[1]; p += 2;
    01699         m_sphli.StopX += (p[0]<<8)|p[1]; p += 2;
    01700         m_sphli.StopY += (p[0]<<8)|p[1]; p += 2;
    01701
    01702         for(int i = 0; i < 4; i++)
    01703         {
    01704                 m_sppal[i].Y = *p++;
    01705                 m_sppal[i].U = *p++;
    01706                 m_sppal[i].V = *p++;
    01707                 m_sppal[i].Reserved = *p++ >> 4;
    01708         }
    01709
    01710         if(*p++&0xc0)
    01711                 p += 4; // duration of the shift operation should be here, but it is untested
    01712
    01713         m_offset[1] = (p[0]<<8)|p[1]; p += 2;
    01714
    01715         m_offset[0] = p - p0;
    01716         m_offset[1] += m_offset[0];
    01717
    01718         return(true);
    01719 }
    01720
    01721 void CSubpicInputPin::svcdspu::Render(BYTE** yuv, int w, int h, AM_DVD_YUV* sppal, bool fsppal)
    01722 {
    01723         BYTE* p = m_pData.GetData();
    01724         DWORD offset[2] = {m_offset[0], m_offset[1]};
    01725
    01726         CRect rcclip(0, 0, w, h);
    01727
    01728         /* FIXME: startx/y looks to be wrong in the sample I tested (yes, this one too!)
    01729         CPoint pt(m_sphli.StartX, m_sphli.StartY);
    01730         CRect rc(pt, CPoint(m_sphli.StopX, m_sphli.StopY));
    01731         */
    01732
    01733         CSize size(m_sphli.StopX - m_sphli.StartX, m_sphli.StopY - m_sphli.StartY);
    01734         CPoint pt((rcclip.Width() - size.cx) / 2, (rcclip.Height()*3 - size.cy*1) / 4);
    01735         CRect rc(pt, size);
    01736
    01737         int nField = 0;
    01738         int n = 3;
    01739
    01740         DWORD end[2] = {offset[1], (p[2]<<8)|p[3]};
    01741
    01742         while((nField == 0 && offset[0] < end[0]) || (nField == 1 && offset[1] < end[1]))
    01743         {
    01744                 BYTE code = GetHalfNibble(p, offset, nField, n);
    01745                 BYTE repeat = 1 + (code == 0 ? GetHalfNibble(p, offset, nField, n) : 0);
    01746
    01747                 DrawPixels(yuv, w, pt, repeat, m_sppal[code&3], rcclip);
    01748                 if((pt.x += repeat) < rc.right) continue;
    01749
    01750                 while(n != 3)
    01751                         GetHalfNibble(p, offset, nField, n); // align to byte
    01752
    01753                 pt.x = rc.left;
    01754                 pt.y++;
    01755                 nField = 1 - nField;
    01756         }
    01757 }
    01758
    01759 //
    01760 // CClosedCaptionOutputPin
    01761 //
    01762
    01763 CClosedCaptionOutputPin::CClosedCaptionOutputPin(CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
    01764         : CBaseOutputPin(NAME("CClosedCaptionOutputPin"), pFilter, pLock, phr, L"~CC")
    01765 {
    01766 }
    01767
    01768 HRESULT CClosedCaptionOutputPin::CheckMediaType(const CMediaType* mtOut)
    01769 {
    01770         return mtOut->majortype == MEDIATYPE_AUXLine21Data && mtOut->subtype == MEDIASUBTYPE_Line21_GOPPacket
    01771                 ? S_OK
    01772                 : VFW_E_TYPE_NOT_ACCEPTED;
    01773 }
    01774
    01775 HRESULT CClosedCaptionOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
    01776 {
    01777         if(iPosition < 0) return E_INVALIDARG;
    01778         if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
    01779
    01780         pmt->InitMediaType();
    01781         pmt->majortype = MEDIATYPE_AUXLine21Data;
    01782         pmt->subtype = MEDIASUBTYPE_Line21_GOPPacket;
    01783         pmt->formattype = FORMAT_None;
    01784
    01785         return S_OK;
    01786 }
    01787
    01788 HRESULT CClosedCaptionOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
    01789 {
    01790         pProperties->cBuffers = 1;
    01791         pProperties->cbBuffer = 2048;
    01792         pProperties->cbAlign = 1;
    01793         pProperties->cbPrefix = 0;
    01794
    01795         HRESULT hr;
    01796         ALLOCATOR_PROPERTIES Actual;
    01797     if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
    01798                 return hr;
    01799
    01800     return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
    01801                 ? E_FAIL
    01802                 : NOERROR;
    01803 }