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 }

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