Mpeg2DecFilter.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:48k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "stdafx.h"
  22. #include <math.h>
  23. #include <atlbase.h>
  24. #include <ks.h>
  25. #include <ksmedia.h>
  26. #include "libmpeg2.h"
  27. #include "Mpeg2DecFilter.h"
  28. #include "......DSUtilDSUtil.h"
  29. #include "......DSUtilMediaTypes.h"
  30. #include <initguid.h>
  31. #include "........includemoreuuids.h"
  32. #include "........includematroskamatroska.h"
  33. #ifdef REGISTER_FILTER
  34. const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
  35. {
  36. {&MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_MPEG2_VIDEO},
  37. {&MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_MPEG2_VIDEO},
  38. {&MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_MPEG2_VIDEO},
  39. {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG2_VIDEO},
  40. {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Packet},
  41. {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Payload},
  42. };
  43. const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
  44. {
  45. {&MEDIATYPE_Video, &MEDIASUBTYPE_IYUV},
  46. };
  47. const AMOVIESETUP_PIN sudpPins[] =
  48. {
  49.     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
  50.     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
  51. };
  52. const AMOVIESETUP_FILTER sudFilter[] =
  53. {
  54. {&__uuidof(CMpeg2DecFilter), L"Mpeg2Dec Filter", 0x40000002, countof(sudpPins), sudpPins},
  55. };
  56. CFactoryTemplate g_Templates[] =
  57. {
  58.     {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CMpeg2DecFilter>, NULL, &sudFilter[0]},
  59. };
  60. int g_cTemplates = countof(g_Templates);
  61. STDAPI DllRegisterServer()
  62. {
  63. return AMovieDllRegisterServer2(TRUE);
  64. }
  65. STDAPI DllUnregisterServer()
  66. {
  67. return AMovieDllRegisterServer2(FALSE);
  68. }
  69. //
  70. #include "........includedetoursdetours.h"
  71. DETOUR_TRAMPOLINE(BOOL WINAPI Real_IsDebuggerPresent(), IsDebuggerPresent);
  72. BOOL WINAPI Mine_IsDebuggerPresent()
  73. {
  74. TRACE(_T("Oops, somebody was trying to be naughty! (called IsDebuggerPresent)n")); 
  75. return FALSE;
  76. }
  77. DETOUR_TRAMPOLINE(LONG WINAPI Real_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam), ChangeDisplaySettingsExA);
  78. DETOUR_TRAMPOLINE(LONG WINAPI Real_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam), ChangeDisplaySettingsExW);
  79. LONG WINAPI Mine_ChangeDisplaySettingsEx(LONG ret, DWORD dwFlags, LPVOID lParam)
  80. {
  81. if(dwFlags&CDS_VIDEOPARAMETERS)
  82. {
  83. VIDEOPARAMETERS* vp = (VIDEOPARAMETERS*)lParam;
  84. if(vp->Guid == GUIDFromCString(_T("{02C62061-1097-11d1-920F-00A024DF156E}"))
  85. && (vp->dwFlags&VP_FLAGS_COPYPROTECT))
  86. {
  87. if(vp->dwCommand == VP_COMMAND_GET)
  88. {
  89. if((vp->dwTVStandard&VP_TV_STANDARD_WIN_VGA) && vp->dwTVStandard != VP_TV_STANDARD_WIN_VGA)
  90. {
  91. TRACE(_T("Ooops, tv-out enabled? macrovision checks suck..."));
  92. vp->dwTVStandard = VP_TV_STANDARD_WIN_VGA;
  93. }
  94. }
  95. else if(vp->dwCommand == VP_COMMAND_SET)
  96. {
  97. TRACE(_T("Ooops, as I already told ya, no need for any macrovision bs here"));
  98. return 0;
  99. }
  100. }
  101. }
  102. return ret;
  103. }
  104. LONG WINAPI Mine_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam)
  105. {
  106. return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExA(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam);
  107. }
  108. LONG WINAPI Mine_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam)
  109. {
  110. return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam);
  111. }
  112. bool fDetourInited = false;
  113. //
  114. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  115. BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
  116. {
  117. if(!fDetourInited)
  118. {
  119. DetourFunctionWithTrampoline((PBYTE)Real_IsDebuggerPresent, (PBYTE)Mine_IsDebuggerPresent);
  120. DetourFunctionWithTrampoline((PBYTE)Real_ChangeDisplaySettingsExA, (PBYTE)Mine_ChangeDisplaySettingsExA);
  121. DetourFunctionWithTrampoline((PBYTE)Real_ChangeDisplaySettingsExW, (PBYTE)Mine_ChangeDisplaySettingsExW);
  122. fDetourInited = true;
  123. }
  124. return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
  125. }
  126. #endif
  127. //
  128. // CMpeg2DecFilter
  129. //
  130. CMpeg2DecFilter::CMpeg2DecFilter(LPUNKNOWN lpunk, HRESULT* phr) 
  131. : CBaseVideoFilter(NAME("CMpeg2DecFilter"), lpunk, phr, __uuidof(this))
  132. , m_fWaitForKeyFrame(true)
  133. {
  134. delete m_pInput;
  135. if(FAILED(*phr)) return;
  136. if(!(m_pInput = new CMpeg2DecInputPin(this, phr, L"Video"))) *phr = E_OUTOFMEMORY;
  137. if(FAILED(*phr)) return;
  138. if(!(m_pSubpicInput = new CSubpicInputPin(this, phr))) *phr = E_OUTOFMEMORY;
  139. if(FAILED(*phr)) return;
  140. if(!(m_pClosedCaptionOutput = new CClosedCaptionOutputPin(this, m_pLock, phr))) *phr = E_OUTOFMEMORY;
  141. if(FAILED(*phr)) return;
  142. SetDeinterlaceMethod(DIAuto);
  143. SetBrightness(0.0);
  144. SetContrast(1.0);
  145. SetHue(0.0);
  146. SetSaturation(1.0);
  147. EnableForcedSubtitles(true);
  148. EnablePlanarYUV(true);
  149. m_rate.Rate = 10000;
  150. m_rate.StartTime = 0;
  151. }
  152. CMpeg2DecFilter::~CMpeg2DecFilter()
  153. {
  154. delete m_pSubpicInput;
  155. delete m_pClosedCaptionOutput;
  156. }
  157. STDMETHODIMP CMpeg2DecFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  158. {
  159. return
  160. QI(IMpeg2DecFilter)
  161.  __super::NonDelegatingQueryInterface(riid, ppv);
  162. }
  163. int CMpeg2DecFilter::GetPinCount()
  164. {
  165. return 4;
  166. }
  167. CBasePin* CMpeg2DecFilter::GetPin(int n)
  168. {
  169. switch(n)
  170. {
  171. case 0: return m_pInput;
  172. case 1: return m_pOutput;
  173. case 2: return m_pSubpicInput;
  174. case 3: return m_pClosedCaptionOutput;
  175. }
  176. return NULL;
  177. }
  178. HRESULT CMpeg2DecFilter::EndOfStream()
  179. {
  180. CAutoLock cAutoLock(&m_csReceive);
  181. m_pClosedCaptionOutput->EndOfStream();
  182. return __super::EndOfStream();
  183. }
  184. HRESULT CMpeg2DecFilter::BeginFlush()
  185. {
  186. m_pClosedCaptionOutput->DeliverBeginFlush();
  187. return __super::BeginFlush();
  188. }
  189. HRESULT CMpeg2DecFilter::EndFlush()
  190. {
  191. m_pClosedCaptionOutput->DeliverEndFlush();
  192. return __super::EndFlush();
  193. }
  194. HRESULT CMpeg2DecFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
  195. {
  196. CAutoLock cAutoLock(&m_csReceive);
  197. m_pClosedCaptionOutput->DeliverNewSegment(tStart, tStop, dRate);
  198. m_fDropFrames = false;
  199. return __super::NewSegment(tStart, tStop, dRate);
  200. }
  201. void CMpeg2DecFilter::InputTypeChanged()
  202. {
  203. CAutoLock cAutoLock(&m_csReceive);
  204. TRACE(_T("ResetMpeg2Decoder()n"));
  205. for(int i = 0; i < countof(m_dec->m_pictures); i++)
  206. {
  207. m_dec->m_pictures[i].rtStart = m_dec->m_pictures[i].rtStop = _I64_MIN+1;
  208. m_dec->m_pictures[i].fDelivered = false;
  209. m_dec->m_pictures[i].flags &= ~PIC_MASK_CODING_TYPE;
  210. }
  211. CMediaType& mt = m_pInput->CurrentMediaType();
  212. BYTE* pSequenceHeader = NULL;
  213. DWORD cbSequenceHeader = 0;
  214. if(mt.formattype == FORMAT_MPEGVideo)
  215. {
  216. pSequenceHeader = ((MPEG1VIDEOINFO*)mt.Format())->bSequenceHeader;
  217. cbSequenceHeader = ((MPEG1VIDEOINFO*)mt.Format())->cbSequenceHeader;
  218. }
  219. else if(mt.formattype == FORMAT_MPEG2_VIDEO)
  220. {
  221. pSequenceHeader = (BYTE*)((MPEG2VIDEOINFO*)mt.Format())->dwSequenceHeader;
  222. cbSequenceHeader = ((MPEG2VIDEOINFO*)mt.Format())->cbSequenceHeader;
  223. }
  224. m_dec->mpeg2_close();
  225. m_dec->mpeg2_init();
  226. m_dec->mpeg2_buffer(pSequenceHeader, pSequenceHeader + cbSequenceHeader);
  227. m_fWaitForKeyFrame = true;
  228. m_fFilm = false;
  229. m_fb.flags = 0;
  230. }
  231. HRESULT CMpeg2DecFilter::Transform(IMediaSample* pIn)
  232. {
  233. HRESULT hr;
  234. BYTE* pDataIn = NULL;
  235. if(FAILED(hr = pIn->GetPointer(&pDataIn)))
  236. return hr;
  237. long len = pIn->GetActualDataLength();
  238. ((CDeCSSInputPin*)m_pInput)->StripPacket(pDataIn, len);
  239. if(pIn->IsDiscontinuity() == S_OK)
  240. {
  241. InputTypeChanged();
  242. }
  243. REFERENCE_TIME rtStart = _I64_MIN, rtStop = _I64_MIN;
  244. hr = pIn->GetTime(&rtStart, &rtStop);
  245. if(FAILED(hr)) rtStart = rtStop = _I64_MIN;
  246. while(len >= 0)
  247. {
  248. mpeg2_state_t state = m_dec->mpeg2_parse();
  249. __asm emms; // this one is missing somewhere in the precompiled mmx obj files
  250. switch(state)
  251. {
  252. case STATE_BUFFER:
  253. if(len == 0) len = -1;
  254. else {m_dec->mpeg2_buffer(pDataIn, pDataIn + len); len = 0;}
  255. break;
  256. case STATE_INVALID:
  257. TRACE(_T("STATE_INVALIDn"));
  258. // if(m_fWaitForKeyFrame)
  259. // ResetMpeg2Decoder();
  260. break;
  261. case STATE_GOP:
  262. // TRACE(_T("STATE_GOPn"));
  263. if(m_dec->m_info.m_user_data_len > 4 && *(DWORD*)m_dec->m_info.m_user_data == 0xf8014343
  264. && m_pClosedCaptionOutput->IsConnected())
  265. {
  266. CComPtr<IMediaSample> pSample;
  267. m_pClosedCaptionOutput->GetDeliveryBuffer(&pSample, NULL, NULL, 0);
  268. BYTE* pData = NULL;
  269. pSample->GetPointer(&pData);
  270. *(DWORD*)pData = 0xb2010000;
  271. memcpy(pData + 4, m_dec->m_info.m_user_data, m_dec->m_info.m_user_data_len);
  272. pSample->SetActualDataLength(m_dec->m_info.m_user_data_len + 4);
  273. m_pClosedCaptionOutput->Deliver(pSample);
  274. }
  275. break;
  276. case STATE_SEQUENCE:
  277. TRACE(_T("STATE_SEQUENCEn"));
  278. m_AvgTimePerFrame = 10i64 * m_dec->m_info.m_sequence->frame_period / 27;
  279. if(m_AvgTimePerFrame == 0) m_AvgTimePerFrame = ((VIDEOINFOHEADER*)m_pInput->CurrentMediaType().Format())->AvgTimePerFrame;
  280. break;
  281. case STATE_PICTURE:
  282. /* {
  283. TCHAR frametype[] = {'?','I', 'P', 'B', 'D'};
  284. TRACE(_T("STATE_PICTURE %010I64d [%c]n"), rtStart, frametype[m_dec->m_picture->flags&PIC_MASK_CODING_TYPE]);
  285. }
  286. */ m_dec->m_picture->rtStart = rtStart;
  287. rtStart = _I64_MIN;
  288. m_dec->m_picture->fDelivered = false;
  289. m_dec->mpeg2_skip(m_fDropFrames && (m_dec->m_picture->flags&PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B);
  290. break;
  291. case STATE_SLICE:
  292. case STATE_END:
  293. {
  294. mpeg2_picture_t* picture = m_dec->m_info.m_display_picture;
  295. mpeg2_picture_t* picture_2nd = m_dec->m_info.m_display_picture_2nd;
  296. mpeg2_fbuf_t* fbuf = m_dec->m_info.m_display_fbuf;
  297. if(picture && fbuf && !(picture->flags&PIC_FLAG_SKIP))
  298. {
  299. ASSERT(!picture->fDelivered);
  300. // start - end
  301. m_fb.rtStart = picture->rtStart;
  302. if(m_fb.rtStart == _I64_MIN) m_fb.rtStart = m_fb.rtStop;
  303. m_fb.rtStop = m_fb.rtStart + m_AvgTimePerFrame * picture->nb_fields / (picture_2nd ? 1 : 2);
  304. REFERENCE_TIME rtStart = m_fb.rtStart;
  305. REFERENCE_TIME rtStop = m_fb.rtStop;
  306. // flags
  307. if(!(m_dec->m_info.m_sequence->flags&SEQ_FLAG_PROGRESSIVE_SEQUENCE)
  308. && (picture->flags&PIC_FLAG_PROGRESSIVE_FRAME))
  309. {
  310. if(!m_fFilm
  311. && (picture->flags&PIC_FLAG_REPEAT_FIRST_FIELD)
  312. && !(m_fb.flags&PIC_FLAG_REPEAT_FIRST_FIELD))
  313. {
  314. TRACE(_T("m_fFilm = truen"));
  315. m_fFilm = true;
  316. }
  317. else if(m_fFilm
  318. && !(picture->flags&PIC_FLAG_REPEAT_FIRST_FIELD)
  319. && !(m_fb.flags&PIC_FLAG_REPEAT_FIRST_FIELD))
  320. {
  321. TRACE(_T("m_fFilm = falsen"));
  322. m_fFilm = false;
  323. }
  324. }
  325. m_fb.flags = picture->flags;
  326. ASSERT(!(m_fb.flags&PIC_FLAG_SKIP));
  327. // frame buffer
  328. int w = m_dec->m_info.m_sequence->picture_width;
  329. int h = m_dec->m_info.m_sequence->picture_height;
  330. int pitch = m_dec->m_info.m_sequence->width;
  331. if(m_fb.w != w || m_fb.h != h || m_fb.pitch != pitch)
  332. m_fb.alloc(w, h, pitch);
  333. // deinterlace
  334. ditype di = GetDeinterlaceMethod();
  335. if(di == DIAuto || di != DIWeave && di != DIBlend && di != DIBob)
  336. {
  337. if(!!(m_dec->m_info.m_sequence->flags&SEQ_FLAG_PROGRESSIVE_SEQUENCE))
  338. di = DIWeave; // hurray!
  339. else if(m_fFilm)
  340. di = DIWeave; // we are lucky
  341. else if(!(m_fb.flags&PIC_FLAG_PROGRESSIVE_FRAME))
  342. di = DIBlend; // ok, clear thing
  343. else
  344. // big trouble here, the progressive_frame bit is not reliable :'(
  345. // frames without temporal field diffs can be only detected when ntsc 
  346. // uses the repeat field flag (signaled with m_fFilm), if it's not set 
  347. // or we have pal then we might end up blending the fields unnecessarily...
  348. di = DIBlend;
  349. // TODO: find out if the pic is really interlaced by analysing it
  350. }
  351. if(di == DIWeave)
  352. {
  353. BitBltFromI420ToI420(w, h, 
  354. m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], pitch, 
  355. fbuf->buf[0], fbuf->buf[1], fbuf->buf[2], pitch);
  356. }
  357. else if(di == DIBlend)
  358. {
  359. DeinterlaceBlend(m_fb.buf[0], fbuf->buf[0], w, h, pitch, pitch);
  360. DeinterlaceBlend(m_fb.buf[1], fbuf->buf[1], w/2, h/2, pitch/2, pitch/2);
  361. DeinterlaceBlend(m_fb.buf[2], fbuf->buf[2], w/2, h/2, pitch/2, pitch/2);
  362. }
  363. else if(di == DIBob)
  364. {
  365. if(m_fb.flags&PIC_FLAG_TOP_FIELD_FIRST)
  366. {
  367. BitBltFromRGBToRGB(w, h/2, m_fb.buf[0], pitch*2, 8, fbuf->buf[0], pitch*2, 8);
  368. AvgLines8(m_fb.buf[0], h, pitch);
  369. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1], pitch, 8, fbuf->buf[1], pitch, 8);
  370. AvgLines8(m_fb.buf[1], h/2, pitch/2);
  371. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2], pitch, 8, fbuf->buf[2], pitch, 8);
  372. AvgLines8(m_fb.buf[2], h/2, pitch/2);
  373. }
  374. else
  375. {
  376. BitBltFromRGBToRGB(w, h/2, m_fb.buf[0]+pitch, pitch*2, 8, fbuf->buf[0]+pitch, pitch*2, 8);
  377. AvgLines8(m_fb.buf[0]+pitch, h-1, pitch);
  378. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1]+pitch/2, pitch, 8, fbuf->buf[1]+pitch/2, pitch, 8);
  379. AvgLines8(m_fb.buf[1]+pitch/2, (h-1)/2, pitch/2);
  380. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2]+pitch/2, pitch, 8, fbuf->buf[2]+pitch/2, pitch, 8);
  381. AvgLines8(m_fb.buf[2]+pitch/2, (h-1)/2, pitch/2);
  382. }
  383. m_fb.rtStart = rtStart;
  384. m_fb.rtStop = (rtStart + rtStop) / 2;
  385. }
  386. // postproc
  387. ApplyBrContHueSat(m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], w, h, pitch);
  388. // deliver
  389. picture->fDelivered = true;
  390. if(FAILED(hr = Deliver(false)))
  391. return hr;
  392. // spec code for bob
  393. if(di == DIBob)
  394. {
  395. if(m_fb.flags&PIC_FLAG_TOP_FIELD_FIRST)
  396. {
  397. BitBltFromRGBToRGB(w, h/2, m_fb.buf[0]+pitch, pitch*2, 8, fbuf->buf[0]+pitch, pitch*2, 8);
  398. AvgLines8(m_fb.buf[0]+pitch, h-1, pitch);
  399. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1]+pitch/2, pitch, 8, fbuf->buf[1]+pitch/2, pitch, 8);
  400. AvgLines8(m_fb.buf[1]+pitch/2, (h-1)/2, pitch/2);
  401. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2]+pitch/2, pitch, 8, fbuf->buf[2]+pitch/2, pitch, 8);
  402. AvgLines8(m_fb.buf[2]+pitch/2, (h-1)/2, pitch/2);
  403. }
  404. else
  405. {
  406. BitBltFromRGBToRGB(w, h/2, m_fb.buf[0], pitch*2, 8, fbuf->buf[0], pitch*2, 8);
  407. AvgLines8(m_fb.buf[0], h, pitch);
  408. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[1], pitch, 8, fbuf->buf[1], pitch, 8);
  409. AvgLines8(m_fb.buf[1], h/2, pitch/2);
  410. BitBltFromRGBToRGB(w/2, h/4, m_fb.buf[2], pitch, 8, fbuf->buf[2], pitch, 8);
  411. AvgLines8(m_fb.buf[2], h/2, pitch/2);
  412. }
  413. m_fb.rtStart = (rtStart + rtStop) / 2;
  414. m_fb.rtStop = rtStop;
  415. // postproc
  416. ApplyBrContHueSat(m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], w, h, pitch);
  417. // deliver
  418. picture->fDelivered = true;
  419. if(FAILED(hr = Deliver(false)))
  420. return hr;
  421. }
  422. }
  423. }
  424. break;
  425. default:
  426.     break;
  427. }
  428.     }
  429. return S_OK;
  430. }
  431. HRESULT CMpeg2DecFilter::Deliver(bool fRepeatLast)
  432. {
  433. CAutoLock cAutoLock(&m_csReceive);
  434. if((m_fb.flags&PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I)
  435. m_fWaitForKeyFrame = false;
  436. TCHAR frametype[] = {'?','I', 'P', 'B', 'D'};
  437. // TRACE(_T("%010I64d - %010I64d [%c] [prsq %d prfr %d tff %d rff %d nb_fields %d ref %d] (%dx%d/%dx%d)n"), 
  438. TRACE(_T("%010I64d - %010I64d [%c] [prsq %d prfr %d tff %d rff %d] (%dx%d %d) (preroll %d)n"), 
  439. m_fb.rtStart, m_fb.rtStop,
  440. frametype[m_fb.flags&PIC_MASK_CODING_TYPE],
  441. !!(m_dec->m_info.m_sequence->flags&SEQ_FLAG_PROGRESSIVE_SEQUENCE),
  442. !!(m_fb.flags&PIC_FLAG_PROGRESSIVE_FRAME),
  443. !!(m_fb.flags&PIC_FLAG_TOP_FIELD_FIRST),
  444. !!(m_fb.flags&PIC_FLAG_REPEAT_FIRST_FIELD),
  445. // m_dec->m_info.m_display_picture->nb_fields,
  446. // m_dec->m_info.m_display_picture->temporal_reference,
  447. m_fb.w, m_fb.h, m_fb.pitch,
  448. !!(m_fb.rtStart < 0 || m_fWaitForKeyFrame));
  449. /**/
  450. if(m_fb.rtStart < 0 || m_fWaitForKeyFrame)
  451. return S_OK;
  452. HRESULT hr;
  453. CComPtr<IMediaSample> pOut;
  454. BYTE* pDataOut = NULL;
  455. if(FAILED(hr = GetDeliveryBuffer(m_fb.w, m_fb.h, &pOut))
  456. || FAILED(hr = pOut->GetPointer(&pDataOut)))
  457. return hr;
  458. {
  459. CMpeg2DecInputPin* pPin = (CMpeg2DecInputPin*)m_pInput;
  460. CAutoLock cAutoLock(&pPin->m_csRateLock);
  461. if(m_rate.Rate != pPin->m_ratechange.Rate)
  462. {
  463. m_rate.Rate = pPin->m_ratechange.Rate;
  464. m_rate.StartTime = m_fb.rtStart;
  465. }
  466. }
  467. REFERENCE_TIME rtStart = m_fb.rtStart;
  468. REFERENCE_TIME rtStop = m_fb.rtStop;
  469. rtStart = m_rate.StartTime + (rtStart - m_rate.StartTime) * m_rate.Rate / 10000;
  470. rtStop = m_rate.StartTime + (rtStop - m_rate.StartTime) * m_rate.Rate / 10000;
  471. pOut->SetTime(&rtStart, &rtStop);
  472. pOut->SetMediaTime(NULL, NULL);
  473. if(m_fb.h == 1088)
  474. {
  475. memset(m_fb.buf[0] + m_fb.w*(m_fb.h-8), 0xff, m_fb.w*8);
  476. memset(m_fb.buf[1] + m_fb.w*(m_fb.h-8)/4, 0x80, m_fb.w*8/4);
  477. memset(m_fb.buf[2] + m_fb.w*(m_fb.h-8)/4, 0x80, m_fb.w*8/4);
  478. }
  479. BYTE** buf = &m_fb.buf[0];
  480. if(m_pSubpicInput->HasAnythingToRender(m_fb.rtStart))
  481. {
  482. BitBltFromI420ToI420(m_fb.w, m_fb.h, 
  483. m_fb.buf[3], m_fb.buf[4], m_fb.buf[5], m_fb.pitch, 
  484. m_fb.buf[0], m_fb.buf[1], m_fb.buf[2], m_fb.pitch);
  485. buf = &m_fb.buf[3];
  486. m_pSubpicInput->RenderSubpics(m_fb.rtStart, buf, m_fb.pitch, m_fb.h);
  487. }
  488. CopyBuffer(pDataOut, buf, (m_fb.w+7)&~7, m_fb.h, m_fb.pitch, MEDIASUBTYPE_I420);
  489. if(FAILED(hr = m_pOutput->Deliver(pOut)))
  490. return hr;
  491. return S_OK;
  492. }
  493. #include "........includeIFilterVersion.h"
  494. [uuid("04FE9017-F873-410E-871E-AB91661A4EF7")]
  495. struct ffdshow {};
  496. [uuid("93A22E7A-5091-45ef-BA61-6DA26156A5D0")]
  497. struct dvs {};
  498. [uuid("9852A670-F845-491b-9BE6-EBD841B8A613")]
  499. struct dvsauto {};
  500. [uuid("fd501043-8ebe-11ce-8183-00aa00577da1")]
  501. struct dladapter {};
  502. HRESULT CMpeg2DecFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
  503. {
  504. if(dir == PINDIR_OUTPUT)
  505. {
  506. if(GetCLSID(m_pInput->GetConnected()) == CLSID_DVDNavigator)
  507. {
  508. // one of these needed for dynamic format changes
  509. CLSID clsid = GetCLSID(pPin);
  510. DWORD ver = 0;
  511. if(CComQIPtr<IFilterVersion> pFV = GetFilterFromPin(pPin))
  512. ver = pFV->GetFilterVersion();
  513. if(clsid != CLSID_OverlayMixer
  514. /*&& clsid != CLSID_OverlayMixer2*/
  515. && clsid != CLSID_VideoMixingRenderer 
  516. && clsid != CLSID_VideoMixingRenderer9
  517. && clsid != __uuidof(ffdshow)
  518. && (clsid != __uuidof(dvs) || ver < 0x0234)
  519. && (clsid != __uuidof(dvsauto) || ver < 0x0234)
  520. && clsid != __uuidof(dladapter))
  521. return E_FAIL;
  522. }
  523. }
  524. return __super::CheckConnect(dir, pPin);
  525. }
  526. HRESULT CMpeg2DecFilter::CheckInputType(const CMediaType* mtIn)
  527. {
  528. if(mtIn->formattype == FORMAT_MPEG2_VIDEO && mtIn->pbFormat)
  529. {
  530. MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mtIn->pbFormat;
  531. if(vih->cbSequenceHeader > 0 && (vih->dwSequenceHeader[0] & 0x00ffffff) != 0x00010000)
  532. return VFW_E_TYPE_NOT_ACCEPTED;
  533. }
  534. return (mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
  535. || mtIn->majortype == MEDIATYPE_MPEG2_PACK && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
  536. || mtIn->majortype == MEDIATYPE_MPEG2_PES && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
  537. || mtIn->majortype == MEDIATYPE_Video && mtIn->subtype == MEDIASUBTYPE_MPEG2_VIDEO
  538. || mtIn->majortype == MEDIATYPE_Video && mtIn->subtype == MEDIASUBTYPE_MPEG1Packet
  539. || mtIn->majortype == MEDIATYPE_Video && mtIn->subtype == MEDIASUBTYPE_MPEG1Payload)
  540. ? S_OK
  541. : VFW_E_TYPE_NOT_ACCEPTED;
  542. }
  543. HRESULT CMpeg2DecFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
  544. {
  545. bool fPlanarYUV = mtOut->subtype == MEDIASUBTYPE_YV12 || mtOut->subtype == MEDIASUBTYPE_I420 || mtOut->subtype == MEDIASUBTYPE_IYUV;
  546. return SUCCEEDED(__super::CheckTransform(mtIn, mtOut))
  547. && (!fPlanarYUV || IsPlanarYUVEnabled())
  548. ? S_OK
  549. : VFW_E_TYPE_NOT_ACCEPTED;
  550. }
  551. HRESULT CMpeg2DecFilter::StartStreaming()
  552. {
  553. HRESULT hr = __super::StartStreaming();
  554. if(FAILED(hr)) return hr;
  555. m_dec.Attach(new CMpeg2Dec());
  556. if(!m_dec) return E_OUTOFMEMORY;
  557. InputTypeChanged();
  558. return S_OK;
  559. }
  560. HRESULT CMpeg2DecFilter::StopStreaming()
  561. {
  562. m_dec.Free();
  563. return __super::StopStreaming();
  564. }
  565. HRESULT CMpeg2DecFilter::AlterQuality(Quality q)
  566. {
  567. if(q.Late > 500*10000i64) m_fDropFrames = true;
  568. else if(q.Late <= 0) m_fDropFrames = false;
  569. // TRACE(_T("CMpeg2DecFilter::AlterQuality: Type=%d, Proportion=%d, Late=%I64d, TimeStamp=%I64dn"), q.Type, q.Proportion, q.Late, q.TimeStamp);
  570. return S_OK;
  571. }
  572. // IMpeg2DecFilter
  573. STDMETHODIMP CMpeg2DecFilter::SetDeinterlaceMethod(ditype di)
  574. {
  575. CAutoLock cAutoLock(&m_csProps);
  576. m_di = di;
  577. return S_OK;
  578. }
  579. STDMETHODIMP_(ditype) CMpeg2DecFilter::GetDeinterlaceMethod()
  580. {
  581. CAutoLock cAutoLock(&m_csProps);
  582. return m_di;
  583. }
  584. void CMpeg2DecFilter::CalcBrCont(BYTE* YTbl, double bright, double cont)
  585. {
  586. int Cont = (int)(cont * 512);
  587. int Bright = (int)bright;
  588. for(int i = 0; i < 256; i++)
  589. {
  590. int y = ((Cont * (i - 16)) >> 9) + Bright + 16;
  591. YTbl[i] = min(max(y, 0), 255);
  592. // YTbl[i] = min(max(y, 16), 235);
  593. }
  594. }
  595. void CMpeg2DecFilter::CalcHueSat(BYTE* UTbl, BYTE* VTbl, double hue, double sat)
  596. {
  597. int Sat = (int)(sat * 512);
  598. double Hue = (hue * 3.1415926) / 180.0;
  599. int Sin = (int)(sin(Hue) * 4096);
  600. int Cos = (int)(cos(Hue) * 4096);
  601. for(int y = 0; y < 256; y++)
  602. {
  603. for(int x = 0; x < 256; x++)
  604. {
  605. int u = x - 128; 
  606. int v = y - 128;
  607. int ux = (u * Cos + v * Sin) >> 12;
  608. v = (v * Cos - u * Sin) >> 12;
  609. u = ((ux * Sat) >> 9) + 128;
  610. v = ((v * Sat) >> 9) + 128;
  611. u = min(max(u, 16), 235);
  612. v = min(max(v, 16), 235);
  613. UTbl[(y << 8) | x] = u;
  614. VTbl[(y << 8) | x] = v;
  615. }
  616. }
  617. }
  618. void CMpeg2DecFilter::ApplyBrContHueSat(BYTE* srcy, BYTE* srcu, BYTE* srcv, int w, int h, int pitch)
  619. {
  620. CAutoLock cAutoLock(&m_csProps);
  621. double EPSILON = 1e-4;
  622. if(fabs(m_bright-0.0) > EPSILON || fabs(m_cont-1.0) > EPSILON)
  623. {
  624. for(int size = pitch*h; size > 0; size--)
  625. {
  626. *srcy++ = m_YTbl[*srcy];
  627. }
  628. }
  629. pitch /= 2;
  630. w /= 2;
  631. h /= 2;
  632. if(fabs(m_hue-0.0) > EPSILON || fabs(m_sat-1.0) > EPSILON)
  633. {
  634. for(int size = pitch*h; size > 0; size--)
  635. {
  636. WORD uv = (*srcv<<8)|*srcu;
  637. *srcu++ = m_UTbl[uv];
  638. *srcv++ = m_VTbl[uv];
  639. }
  640. }
  641. }
  642. STDMETHODIMP CMpeg2DecFilter::SetBrightness(double bright)
  643. {
  644. CAutoLock cAutoLock(&m_csProps);
  645. CalcBrCont(m_YTbl, m_bright = bright, m_cont);
  646. return S_OK;
  647. }
  648. STDMETHODIMP CMpeg2DecFilter::SetContrast(double cont)
  649. {
  650. CAutoLock cAutoLock(&m_csProps);
  651. CalcBrCont(m_YTbl, m_bright, m_cont = cont);
  652. return S_OK;
  653. }
  654. STDMETHODIMP CMpeg2DecFilter::SetHue(double hue)
  655. {
  656. CAutoLock cAutoLock(&m_csProps);
  657. CalcHueSat(m_UTbl, m_VTbl, m_hue = hue, m_sat);
  658. return S_OK;
  659. }
  660. STDMETHODIMP CMpeg2DecFilter::SetSaturation(double sat)
  661. {
  662. CAutoLock cAutoLock(&m_csProps);
  663. CalcHueSat(m_UTbl, m_VTbl, m_hue, m_sat = sat);
  664. return S_OK;
  665. }
  666. STDMETHODIMP_(double) CMpeg2DecFilter::GetBrightness()
  667. {
  668. CAutoLock cAutoLock(&m_csProps);
  669. return m_bright;
  670. }
  671. STDMETHODIMP_(double) CMpeg2DecFilter::GetContrast()
  672. {
  673. CAutoLock cAutoLock(&m_csProps);
  674. return m_cont;
  675. }
  676. STDMETHODIMP_(double) CMpeg2DecFilter::GetHue()
  677. {
  678. CAutoLock cAutoLock(&m_csProps);
  679. return m_hue;
  680. }
  681. STDMETHODIMP_(double) CMpeg2DecFilter::GetSaturation()
  682. {
  683. CAutoLock cAutoLock(&m_csProps);
  684. return m_sat;
  685. }
  686. STDMETHODIMP CMpeg2DecFilter::EnableForcedSubtitles(bool fEnable)
  687. {
  688. CAutoLock cAutoLock(&m_csProps);
  689. m_fForcedSubs = fEnable;
  690. return S_OK;
  691. }
  692. STDMETHODIMP_(bool) CMpeg2DecFilter::IsForcedSubtitlesEnabled()
  693. {
  694. CAutoLock cAutoLock(&m_csProps);
  695. return m_fForcedSubs;
  696. }
  697. STDMETHODIMP CMpeg2DecFilter::EnablePlanarYUV(bool fEnable)
  698. {
  699. CAutoLock cAutoLock(&m_csProps);
  700. m_fPlanarYUV = fEnable;
  701. return S_OK;
  702. }
  703. STDMETHODIMP_(bool) CMpeg2DecFilter::IsPlanarYUVEnabled()
  704. {
  705. CAutoLock cAutoLock(&m_csProps);
  706. return m_fPlanarYUV;
  707. }
  708. //
  709. // CMpeg2DecInputPin
  710. //
  711. CMpeg2DecInputPin::CMpeg2DecInputPin(CTransformFilter* pFilter, HRESULT* phr, LPWSTR pName)
  712. : CDeCSSInputPin(NAME("CMpeg2DecInputPin"), pFilter, phr, pName)
  713. {
  714. m_CorrectTS = 0;
  715. m_ratechange.Rate = 10000;
  716. m_ratechange.StartTime = _I64_MAX;
  717. }
  718. // IKsPropertySet
  719. STDMETHODIMP CMpeg2DecInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength)
  720. {
  721. if(PropSet != AM_KSPROPSETID_TSRateChange /*&& PropSet != AM_KSPROPSETID_DVD_RateChange*/)
  722. return __super::Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength);
  723. if(PropSet == AM_KSPROPSETID_TSRateChange)
  724. switch(Id)
  725. {
  726. case AM_RATE_SimpleRateChange:
  727. {
  728. AM_SimpleRateChange* p = (AM_SimpleRateChange*)pPropertyData;
  729. if(!m_CorrectTS) return E_PROP_ID_UNSUPPORTED;
  730. CAutoLock cAutoLock(&m_csRateLock);
  731. m_ratechange = *p;
  732. DbgLog((LOG_TRACE, 0, _T("StartTime=%I64d, Rate=%d"), p->StartTime, p->Rate));
  733. }
  734. break;
  735. case AM_RATE_UseRateVersion:
  736. {
  737. WORD* p = (WORD*)pPropertyData;
  738. if(*p > 0x0101) return E_PROP_ID_UNSUPPORTED;
  739. }
  740. break;
  741. case AM_RATE_CorrectTS:
  742. {
  743. LONG* p = (LONG*)pPropertyData;
  744. m_CorrectTS = *p;
  745. }
  746. break;
  747. default:
  748. return E_PROP_ID_UNSUPPORTED;
  749. }
  750. /*
  751. if(PropSet == AM_KSPROPSETID_DVD_RateChange)
  752. switch(Id)
  753. {
  754. case AM_RATE_ChangeRate:
  755. {
  756. AM_DVD_ChangeRate* p = (AM_DVD_ChangeRate*)pPropertyData;
  757. }
  758. break;
  759. default:
  760. return E_PROP_ID_UNSUPPORTED;
  761. }
  762. */
  763. return S_OK;
  764. }
  765. STDMETHODIMP CMpeg2DecInputPin::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned)
  766. {
  767. if(PropSet != AM_KSPROPSETID_TSRateChange /*&& PropSet != AM_KSPROPSETID_DVD_RateChange*/)
  768. return __super::Get(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength, pBytesReturned);
  769. if(PropSet == AM_KSPROPSETID_TSRateChange)
  770. switch(Id)
  771. {
  772. case AM_RATE_SimpleRateChange:
  773. {
  774. AM_SimpleRateChange* p = (AM_SimpleRateChange*)pPropertyData;
  775. return E_PROP_ID_UNSUPPORTED;
  776. }
  777. break;
  778. case AM_RATE_MaxFullDataRate:
  779. {
  780. AM_MaxFullDataRate* p = (AM_MaxFullDataRate*)pPropertyData;
  781. *p = 8*10000;
  782. *pBytesReturned = sizeof(AM_MaxFullDataRate);
  783. }
  784. break;
  785. case AM_RATE_QueryFullFrameRate:
  786. {
  787. AM_QueryRate* p = (AM_QueryRate*)pPropertyData;
  788. p->lMaxForwardFullFrame = 8*10000;
  789. p->lMaxReverseFullFrame = 8*10000;
  790. *pBytesReturned = sizeof(AM_QueryRate);
  791. }
  792. break;
  793. case AM_RATE_QueryLastRateSegPTS:
  794. {
  795. REFERENCE_TIME* p = (REFERENCE_TIME*)pPropertyData;
  796. return E_PROP_ID_UNSUPPORTED;
  797. }
  798. break;
  799. default:
  800. return E_PROP_ID_UNSUPPORTED;
  801. }
  802. /*
  803. if(PropSet == AM_KSPROPSETID_DVD_RateChange)
  804. switch(Id)
  805. {
  806. case AM_RATE_FullDataRateMax:
  807. {
  808. AM_MaxFullDataRate* p = (AM_MaxFullDataRate*)pPropertyData;
  809. }
  810. break;
  811. case AM_RATE_ReverseDecode:
  812. {
  813. LONG* p = (LONG*)pPropertyData;
  814. }
  815. break;
  816. case AM_RATE_DecoderPosition:
  817. {
  818. AM_DVD_DecoderPosition* p = (AM_DVD_DecoderPosition*)pPropertyData;
  819. }
  820. break;
  821. case AM_RATE_DecoderVersion:
  822. {
  823. LONG* p = (LONG*)pPropertyData;
  824. }
  825. break;
  826. default:
  827. return E_PROP_ID_UNSUPPORTED;
  828. }
  829. */
  830. return S_OK;
  831. }
  832. STDMETHODIMP CMpeg2DecInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport)
  833. {
  834. if(PropSet != AM_KSPROPSETID_TSRateChange /*&& PropSet != AM_KSPROPSETID_DVD_RateChange*/)
  835. return __super::QuerySupported(PropSet, Id, pTypeSupport);
  836. if(PropSet == AM_KSPROPSETID_TSRateChange)
  837. switch(Id)
  838. {
  839. case AM_RATE_SimpleRateChange:
  840. *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET;
  841. break;
  842. case AM_RATE_MaxFullDataRate:
  843. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  844. break;
  845. case AM_RATE_UseRateVersion:
  846. *pTypeSupport = KSPROPERTY_SUPPORT_SET;
  847. break;
  848. case AM_RATE_QueryFullFrameRate:
  849. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  850. break;
  851. case AM_RATE_QueryLastRateSegPTS:
  852. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  853. break;
  854. case AM_RATE_CorrectTS:
  855. *pTypeSupport = KSPROPERTY_SUPPORT_SET;
  856. break;
  857. default:
  858. return E_PROP_ID_UNSUPPORTED;
  859. }
  860. /*
  861. if(PropSet == AM_KSPROPSETID_DVD_RateChange)
  862. switch(Id)
  863. {
  864. case AM_RATE_ChangeRate:
  865. *pTypeSupport = KSPROPERTY_SUPPORT_SET;
  866. break;
  867. case AM_RATE_FullDataRateMax:
  868. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  869. break;
  870. case AM_RATE_ReverseDecode:
  871. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  872. break;
  873. case AM_RATE_DecoderPosition:
  874. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  875. break;
  876. case AM_RATE_DecoderVersion:
  877. *pTypeSupport = KSPROPERTY_SUPPORT_GET;
  878. break;
  879. default:
  880. return E_PROP_ID_UNSUPPORTED;
  881. }
  882. */
  883. return S_OK;
  884. }
  885. //
  886. // CSubpicInputPin
  887. //
  888. #define PTS2RT(pts) (10000i64*pts/90)
  889. CSubpicInputPin::CSubpicInputPin(CTransformFilter* pFilter, HRESULT* phr) 
  890. : CMpeg2DecInputPin(pFilter, phr, L"SubPicture")
  891. , m_spon(TRUE)
  892. , m_fsppal(false)
  893. {
  894. m_sppal[0].Y = 0x00;
  895. m_sppal[0].U = m_sppal[0].V = 0x80;
  896. m_sppal[1].Y = 0xe0;
  897. m_sppal[1].U = m_sppal[1].V = 0x80;
  898. m_sppal[2].Y = 0x80;
  899. m_sppal[2].U = m_sppal[2].V = 0x80;
  900. m_sppal[3].Y = 0x20;
  901. m_sppal[3].U = m_sppal[3].V = 0x80;
  902. }
  903. HRESULT CSubpicInputPin::CheckMediaType(const CMediaType* mtIn)
  904. {
  905. return (mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK
  906. || mtIn->majortype == MEDIATYPE_MPEG2_PACK
  907. || mtIn->majortype == MEDIATYPE_MPEG2_PES
  908. || mtIn->majortype == MEDIATYPE_Video) 
  909. && (mtIn->subtype == MEDIASUBTYPE_DVD_SUBPICTURE
  910. || mtIn->subtype == MEDIASUBTYPE_CVD_SUBPICTURE
  911. || mtIn->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE)
  912. ? S_OK
  913. : VFW_E_TYPE_NOT_ACCEPTED;
  914. }
  915. HRESULT CSubpicInputPin::SetMediaType(const CMediaType* mtIn)
  916. {
  917. return CBasePin::SetMediaType(mtIn);
  918. }
  919. bool CSubpicInputPin::HasAnythingToRender(REFERENCE_TIME rt)
  920. {
  921. if(!IsConnected()) return(false);
  922. CAutoLock cAutoLock(&m_csReceive);
  923. POSITION pos = m_sps.GetHeadPosition();
  924. while(pos)
  925. {
  926. spu* sp = m_sps.GetNext(pos);
  927. if(sp->m_rtStart <= rt && rt < sp->m_rtStop && (/*sp->m_psphli ||*/ sp->m_fForced || m_spon))
  928. return(true);
  929. }
  930. return(false);
  931. }
  932. void CSubpicInputPin::RenderSubpics(REFERENCE_TIME rt, BYTE** yuv, int w, int h)
  933. {
  934. CAutoLock cAutoLock(&m_csReceive);
  935. POSITION pos;
  936. // remove no longer needed things first
  937. pos = m_sps.GetHeadPosition();
  938. while(pos)
  939. {
  940. POSITION cur = pos;
  941. spu* sp = m_sps.GetNext(pos);
  942. if(sp->m_rtStop <= rt) m_sps.RemoveAt(cur);
  943. }
  944. pos = m_sps.GetHeadPosition();
  945. while(pos)
  946. {
  947. spu* sp = m_sps.GetNext(pos);
  948. if(sp->m_rtStart <= rt && rt < sp->m_rtStop 
  949. && (m_spon || sp->m_fForced && (((CMpeg2DecFilter*)m_pFilter)->IsForcedSubtitlesEnabled() || sp->m_psphli)))
  950. sp->Render(yuv, w, h, m_sppal, m_fsppal);
  951. }
  952. }
  953. HRESULT CSubpicInputPin::Transform(IMediaSample* pSample)
  954. {
  955. HRESULT hr;
  956. AM_MEDIA_TYPE* pmt;
  957. if(SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt)
  958. {
  959. CMediaType mt(*pmt);
  960. SetMediaType(&mt);
  961. DeleteMediaType(pmt);
  962. }
  963. BYTE* pDataIn = NULL;
  964. if(FAILED(hr = pSample->GetPointer(&pDataIn))) return hr;
  965. long len = pSample->GetActualDataLength();
  966. StripPacket(pDataIn, len);
  967. if(len <= 0) return S_FALSE;
  968. if(m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE)
  969. {
  970. pDataIn += 4;
  971. len -= 4;
  972. }
  973. if(len <= 0) return S_FALSE;
  974. CAutoLock cAutoLock(&m_csReceive);
  975. REFERENCE_TIME rtStart = 0, rtStop = 0;
  976. hr = pSample->GetTime(&rtStart, &rtStop);
  977. bool fRefresh = false;
  978. if(FAILED(hr))
  979. {
  980. if(!m_sps.IsEmpty())
  981. {
  982. spu* sp = m_sps.GetTail();
  983. sp->m_pData.SetSize(sp->m_pData.GetSize() + len);
  984. memcpy(sp->m_pData.GetData() + sp->m_pData.GetSize() - len, pDataIn, len);
  985. }
  986. }
  987. else
  988. {
  989. POSITION pos = m_sps.GetTailPosition();
  990. while(pos)
  991. {
  992. POSITION cur = pos;
  993. spu* sp = m_sps.GetPrev(pos);
  994. if(sp->m_rtStop == _I64_MAX)
  995. {
  996. sp->m_rtStop = rtStart;
  997. break;
  998. }
  999. }
  1000. CAutoPtr<spu> p;
  1001. if(m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE) p.Attach(new dvdspu());
  1002. else if(m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE) p.Attach(new cvdspu());
  1003. else if(m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE) p.Attach(new svcdspu());
  1004. else return E_FAIL;
  1005. p->m_rtStart = rtStart;
  1006. p->m_rtStop = _I64_MAX;
  1007. p->m_pData.SetSize(len);
  1008. memcpy(p->m_pData.GetData(), pDataIn, len);
  1009. if(m_sphli && p->m_rtStart == PTS2RT(m_sphli->StartPTM))
  1010. {
  1011. p->m_psphli = m_sphli;
  1012. fRefresh = true;
  1013. }
  1014. m_sps.AddTail(p);
  1015. }
  1016. if(!m_sps.IsEmpty())
  1017. {
  1018. m_sps.GetTail()->Parse();
  1019. }
  1020. if(fRefresh)
  1021. {
  1022. // ((CMpeg2DecFilter*)m_pFilter)->Deliver(true);
  1023. }
  1024. return S_FALSE;
  1025. }
  1026. STDMETHODIMP CSubpicInputPin::EndFlush()
  1027. {
  1028. CAutoLock cAutoLock(&m_csReceive);
  1029. m_sps.RemoveAll();
  1030. return S_OK;
  1031. }
  1032. // IKsPropertySet
  1033. STDMETHODIMP CSubpicInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength)
  1034. {
  1035. if(PropSet != AM_KSPROPSETID_DvdSubPic)
  1036. return __super::Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength);
  1037. bool fRefresh = false;
  1038. switch(Id)
  1039. {
  1040. case AM_PROPERTY_DVDSUBPIC_PALETTE:
  1041. {
  1042. CAutoLock cAutoLock(&m_csReceive);
  1043. AM_PROPERTY_SPPAL* pSPPAL = (AM_PROPERTY_SPPAL*)pPropertyData;
  1044. memcpy(m_sppal, pSPPAL->sppal, sizeof(AM_PROPERTY_SPPAL));
  1045. m_fsppal = true;
  1046. DbgLog((LOG_TRACE, 0, _T("new palette")));
  1047. }
  1048. break;
  1049. case AM_PROPERTY_DVDSUBPIC_HLI:
  1050. {
  1051. CAutoLock cAutoLock(&m_csReceive);
  1052. AM_PROPERTY_SPHLI* pSPHLI = (AM_PROPERTY_SPHLI*)pPropertyData;
  1053. m_sphli.Free();
  1054. if(pSPHLI->HLISS)
  1055. {
  1056. POSITION pos = m_sps.GetHeadPosition();
  1057. while(pos)
  1058. {
  1059. spu* sp = m_sps.GetNext(pos);
  1060. if(sp->m_rtStart <= PTS2RT(pSPHLI->StartPTM) && PTS2RT(pSPHLI->StartPTM) < sp->m_rtStop)
  1061. {
  1062. fRefresh = true;
  1063. sp->m_psphli.Free();
  1064. sp->m_psphli.Attach(new AM_PROPERTY_SPHLI());
  1065. memcpy((AM_PROPERTY_SPHLI*)sp->m_psphli, pSPHLI, sizeof(AM_PROPERTY_SPHLI));
  1066. }
  1067. }
  1068. if(!fRefresh) // save it for later, a subpic might be late for this hli
  1069. {
  1070. m_sphli.Attach(new AM_PROPERTY_SPHLI());
  1071. memcpy((AM_PROPERTY_SPHLI*)m_sphli, pSPHLI, sizeof(AM_PROPERTY_SPHLI));
  1072. }
  1073. }
  1074. else
  1075. {
  1076. POSITION pos = m_sps.GetHeadPosition();
  1077. while(pos)
  1078. {
  1079. spu* sp = m_sps.GetNext(pos);
  1080. fRefresh |= !!sp->m_psphli;
  1081. sp->m_psphli.Free();
  1082. }
  1083. }
  1084. if(pSPHLI->HLISS)
  1085. DbgLog((LOG_TRACE, 0, _T("hli: %I64d - %I64d, (%d,%d) - (%d,%d)"), 
  1086. PTS2RT(pSPHLI->StartPTM)/10000, PTS2RT(pSPHLI->EndPTM)/10000,
  1087. pSPHLI->StartX, pSPHLI->StartY, pSPHLI->StopX, pSPHLI->StopY));
  1088. }
  1089. break;
  1090. case AM_PROPERTY_DVDSUBPIC_COMPOSIT_ON:
  1091. {
  1092. CAutoLock cAutoLock(&m_csReceive);
  1093. AM_PROPERTY_COMPOSIT_ON* pCompositOn = (AM_PROPERTY_COMPOSIT_ON*)pPropertyData;
  1094. m_spon = *pCompositOn;
  1095. }
  1096. break;
  1097. default:
  1098. return E_PROP_ID_UNSUPPORTED;
  1099. }
  1100. if(fRefresh)
  1101. {
  1102. ((CMpeg2DecFilter*)m_pFilter)->Deliver(true);
  1103. }
  1104. return S_OK;
  1105. }
  1106. STDMETHODIMP CSubpicInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport)
  1107. {
  1108. if(PropSet != AM_KSPROPSETID_DvdSubPic)
  1109. return __super::QuerySupported(PropSet, Id, pTypeSupport);
  1110. switch(Id)
  1111. {
  1112. case AM_PROPERTY_DVDSUBPIC_PALETTE:
  1113. *pTypeSupport = KSPROPERTY_SUPPORT_SET;
  1114. break;
  1115. case AM_PROPERTY_DVDSUBPIC_HLI:
  1116. *pTypeSupport = KSPROPERTY_SUPPORT_SET;
  1117. break;
  1118. case AM_PROPERTY_DVDSUBPIC_COMPOSIT_ON:
  1119. *pTypeSupport = KSPROPERTY_SUPPORT_SET;
  1120. break;
  1121. default:
  1122. return E_PROP_ID_UNSUPPORTED;
  1123. }
  1124. return S_OK;
  1125. }
  1126. // CSubpicInputPin::spu
  1127. static __inline BYTE GetNibble(BYTE* p, DWORD* offset, int& nField, int& fAligned)
  1128. {
  1129. BYTE ret = (p[offset[nField]] >> (fAligned << 2)) & 0x0f;
  1130. offset[nField] += 1-fAligned;
  1131. fAligned = !fAligned;
  1132.     return ret;
  1133. }
  1134. static __inline BYTE GetHalfNibble(BYTE* p, DWORD* offset, int& nField, int& n)
  1135. {
  1136. BYTE ret = (p[offset[nField]] >> (n << 1)) & 0x03;
  1137. if(!n) offset[nField]++;
  1138. n = (n-1+4)&3;
  1139.     return ret;
  1140. }
  1141. static __inline void DrawPixel(BYTE** yuv, CPoint pt, int pitch, AM_DVD_YUV& c)
  1142. {
  1143. if(c.Reserved == 0) return;
  1144. BYTE* p = &yuv[0][pt.y*pitch + pt.x];
  1145. // *p = (*p*(15-contrast) + sppal[color].Y*contrast)>>4;
  1146. *p -= (*p - c.Y) * c.Reserved >> 4;
  1147. if(pt.y&1) return; // since U/V is half res there is no need to overwrite the same line again
  1148. pt.x = (pt.x + 1) / 2;
  1149. pt.y = (pt.y /*+ 1*/) / 2; // only paint the upper field always, don't round it
  1150. pitch /= 2;
  1151. // U/V is exchanged? wierd but looks true when comparing the outputted colors from other decoders
  1152. p = &yuv[1][pt.y*pitch + pt.x];
  1153. // *p = (BYTE)(((((int)*p-0x80)*(15-contrast) + ((int)sppal[color].V-0x80)*contrast) >> 4) + 0x80);
  1154. *p -= (*p - c.V) * c.Reserved >> 4;
  1155. p = &yuv[2][pt.y*pitch + pt.x];
  1156. // *p = (BYTE)(((((int)*p-0x80)*(15-contrast) + ((int)sppal[color].U-0x80)*contrast) >> 4) + 0x80);
  1157. *p -= (*p - c.U) * c.Reserved >> 4;
  1158. // Neighter of the blending formulas are accurate (">>4" should be "/15").
  1159. // Even though the second one is a bit worse, since we are scaling the difference only,
  1160. // the error is still not noticable.
  1161. }
  1162. static __inline void DrawPixels(BYTE** yuv, int pitch, CPoint pt, int len, AM_DVD_YUV& c, CRect& rc)
  1163. {
  1164.     if(pt.y < rc.top || pt.y >= rc.bottom) return;
  1165. if(pt.x < rc.left) {len -= rc.left - pt.x; pt.x = rc.left;}
  1166. if(pt.x + len > rc.right) len = rc.right - pt.x;
  1167. if(len <= 0 || pt.x >= rc.right) return;
  1168. if(c.Reserved == 0)
  1169. {
  1170. if(rc.IsRectEmpty())
  1171. return;
  1172. if(pt.y < rc.top || pt.y >= rc.bottom 
  1173. || pt.x+len < rc.left || pt.x >= rc.right)
  1174. return;
  1175. }
  1176. while(len-- > 0)
  1177. {
  1178. DrawPixel(yuv, pt, pitch, c);
  1179. pt.x++;
  1180. }
  1181. }
  1182. // CSubpicInputPin::dvdspu
  1183. bool CSubpicInputPin::dvdspu::Parse()
  1184. {
  1185. BYTE* p = m_pData.GetData();
  1186. WORD packetsize = (p[0]<<8)|p[1];
  1187. WORD datasize = (p[2]<<8)|p[3];
  1188.     if(packetsize > m_pData.GetSize() || datasize > packetsize)
  1189. return(false);
  1190. int i, next = datasize;
  1191. #define GetWORD (p[i]<<8)|p[i+1]; i += 2
  1192. do
  1193. {
  1194. i = next;
  1195. int pts = GetWORD;
  1196. next = GetWORD;
  1197. if(next > packetsize || next < datasize)
  1198. return(false);
  1199. for(bool fBreak = false; !fBreak; )
  1200. {
  1201. int len = 0;
  1202. switch(p[i])
  1203. {
  1204. case 0x00: len = 0; break;
  1205. case 0x01: len = 0; break;
  1206. case 0x02: len = 0; break;
  1207. case 0x03: len = 2; break;
  1208. case 0x04: len = 2; break;
  1209. case 0x05: len = 6; break;
  1210. case 0x06: len = 4; break;
  1211. default: len = 0; break;
  1212. }
  1213. if(i+len >= packetsize)
  1214. {
  1215. TRACE(_T("Warning: Wrong subpicture parameter block endingn"));
  1216. break;
  1217. }
  1218. switch(p[i++])
  1219. {
  1220. case 0x00: // forced start displaying
  1221. m_fForced = true;
  1222. break;
  1223. case 0x01: // normal start displaying
  1224. m_fForced = false;
  1225. break;
  1226. case 0x02: // stop displaying
  1227. m_rtStop = m_rtStart + 1024*PTS2RT(pts);
  1228. break;
  1229. case 0x03:
  1230. m_sphli.ColCon.emph2col = p[i]>>4;
  1231. m_sphli.ColCon.emph1col = p[i]&0xf;
  1232. m_sphli.ColCon.patcol = p[i+1]>>4;
  1233. m_sphli.ColCon.backcol = p[i+1]&0xf;
  1234. i += 2;
  1235. break;
  1236. case 0x04:
  1237. m_sphli.ColCon.emph2con = p[i]>>4;
  1238. m_sphli.ColCon.emph1con = p[i]&0xf;
  1239. m_sphli.ColCon.patcon = p[i+1]>>4;
  1240. m_sphli.ColCon.backcon = p[i+1]&0xf;
  1241. i += 2;
  1242. break;
  1243. case 0x05:
  1244. m_sphli.StartX = (p[i]<<4) + (p[i+1]>>4);
  1245. m_sphli.StopX = ((p[i+1]&0x0f)<<8) + p[i+2]+1;
  1246. m_sphli.StartY = (p[i+3]<<4) + (p[i+4]>>4);
  1247. m_sphli.StopY = ((p[i+4]&0x0f)<<8) + p[i+5]+1;
  1248. i += 6;
  1249. break;
  1250. case 0x06:
  1251. m_offset[0] = GetWORD;
  1252. m_offset[1] = GetWORD;
  1253. break;
  1254. case 0xff: // end of ctrlblk
  1255. fBreak = true;
  1256. continue;
  1257. default: // skip this ctrlblk
  1258. fBreak = true;
  1259. break;
  1260. }
  1261. }
  1262. }
  1263. while(i <= next && i < packetsize);
  1264. return(true);
  1265. }
  1266. void CSubpicInputPin::dvdspu::Render(BYTE** yuv, int w, int h, AM_DVD_YUV* sppal, bool fsppal)
  1267. {
  1268. BYTE* p = m_pData.GetData();
  1269. DWORD offset[2] = {m_offset[0], m_offset[1]};
  1270. AM_PROPERTY_SPHLI sphli = m_sphli;
  1271. CPoint pt(sphli.StartX, sphli.StartY);
  1272. CRect rc(pt, CPoint(sphli.StopX, sphli.StopY));
  1273. CRect rcclip(0, 0, w, h);
  1274. rcclip &= rc;
  1275. if(m_psphli)
  1276. {
  1277. rcclip &= CRect(m_psphli->StartX, m_psphli->StartY, m_psphli->StopX, m_psphli->StopY);
  1278. sphli = *m_psphli;
  1279. }
  1280. AM_DVD_YUV pal[4];
  1281. pal[0] = sppal[fsppal ? sphli.ColCon.backcol : 0];
  1282. pal[0].Reserved = sphli.ColCon.backcon;
  1283. pal[1] = sppal[fsppal ? sphli.ColCon.patcol : 1];
  1284. pal[1].Reserved = sphli.ColCon.patcon;
  1285. pal[2] = sppal[fsppal ? sphli.ColCon.emph1col : 2];
  1286. pal[2].Reserved = sphli.ColCon.emph1con;
  1287. pal[3] = sppal[fsppal ? sphli.ColCon.emph2col : 3];
  1288. pal[3].Reserved = sphli.ColCon.emph2con;
  1289. int nField = 0;
  1290. int fAligned = 1;
  1291. DWORD end[2] = {offset[1], (p[2]<<8)|p[3]};
  1292. while((nField == 0 && offset[0] < end[0]) || (nField == 1 && offset[1] < end[1]))
  1293. {
  1294. DWORD code;
  1295. if((code = GetNibble(p, offset, nField, fAligned)) >= 0x4
  1296. || (code = (code << 4) | GetNibble(p, offset, nField, fAligned)) >= 0x10
  1297. || (code = (code << 4) | GetNibble(p, offset, nField, fAligned)) >= 0x40
  1298. || (code = (code << 4) | GetNibble(p, offset, nField, fAligned)) >= 0x100)
  1299. {
  1300. DrawPixels(yuv, w, pt, code >> 2, pal[code&3], rcclip);
  1301. if((pt.x += code >> 2) < rc.right) continue;
  1302. }
  1303. DrawPixels(yuv, w, pt, rc.right - pt.x, pal[code&3], rcclip);
  1304. if(!fAligned) GetNibble(p, offset, nField, fAligned); // align to byte
  1305. pt.x = rc.left;
  1306. pt.y++;
  1307. nField = 1 - nField;
  1308. }
  1309. }
  1310. // CSubpicInputPin::cvdspu
  1311. bool CSubpicInputPin::cvdspu::Parse()
  1312. {
  1313. BYTE* p = m_pData.GetData();
  1314. WORD packetsize = (p[0]<<8)|p[1];
  1315. WORD datasize = (p[2]<<8)|p[3];
  1316.     if(packetsize > m_pData.GetSize() || datasize > packetsize)
  1317. return(false);
  1318. p = m_pData.GetData() + datasize;
  1319. for(int i = datasize, j = packetsize-4; i <= j; i+=4, p+=4)
  1320. {
  1321. switch(p[0])
  1322. {
  1323. case 0x0c: 
  1324. break;
  1325. case 0x04: 
  1326. m_rtStop = m_rtStart + 10000i64*((p[1]<<16)|(p[2]<<8)|p[3])/90;
  1327. break;
  1328. case 0x17: 
  1329. m_sphli.StartX = ((p[1]&0x0f)<<6) + (p[2]>>2);
  1330. m_sphli.StartY = ((p[2]&0x03)<<8) + p[3];
  1331. break;
  1332. case 0x1f: 
  1333. m_sphli.StopX = ((p[1]&0x0f)<<6) + (p[2]>>2);
  1334. m_sphli.StopY = ((p[2]&0x03)<<8) + p[3];
  1335. break;
  1336. case 0x24: case 0x25: case 0x26: case 0x27: 
  1337. m_sppal[0][p[0]-0x24].Y = p[1];
  1338. m_sppal[0][p[0]-0x24].U = p[2];
  1339. m_sppal[0][p[0]-0x24].V = p[3];
  1340. break;
  1341. case 0x2c: case 0x2d: case 0x2e: case 0x2f: 
  1342. m_sppal[1][p[0]-0x2c].Y = p[1];
  1343. m_sppal[1][p[0]-0x2c].U = p[2];
  1344. m_sppal[1][p[0]-0x2c].V = p[3];
  1345. break;
  1346. case 0x37: 
  1347. m_sppal[0][3].Reserved = p[2]>>4;
  1348. m_sppal[0][2].Reserved = p[2]&0xf;
  1349. m_sppal[0][1].Reserved = p[3]>>4;
  1350. m_sppal[0][0].Reserved = p[3]&0xf;
  1351. break;
  1352. case 0x3f: 
  1353. m_sppal[1][3].Reserved = p[2]>>4;
  1354. m_sppal[1][2].Reserved = p[2]&0xf;
  1355. m_sppal[1][1].Reserved = p[3]>>4;
  1356. m_sppal[1][0].Reserved = p[3]&0xf;
  1357. break;
  1358. case 0x47: 
  1359. m_offset[0] = (p[2]<<8)|p[3];
  1360. break;
  1361. case 0x4f: 
  1362. m_offset[1] = (p[2]<<8)|p[3];
  1363. break;
  1364. default: 
  1365. break;
  1366. }
  1367. }
  1368. return(true);
  1369. }
  1370. void CSubpicInputPin::cvdspu::Render(BYTE** yuv, int w, int h, AM_DVD_YUV* sppal, bool fsppal)
  1371. {
  1372. BYTE* p = m_pData.GetData();
  1373. DWORD offset[2] = {m_offset[0], m_offset[1]};
  1374. CRect rcclip(0, 0, w, h);
  1375. /* FIXME: startx/y looks to be wrong in the sample I tested
  1376. CPoint pt(m_sphli.StartX, m_sphli.StartY);
  1377. CRect rc(pt, CPoint(m_sphli.StopX, m_sphli.StopY));
  1378. */
  1379. CSize size(m_sphli.StopX - m_sphli.StartX, m_sphli.StopY - m_sphli.StartY);
  1380. CPoint pt((rcclip.Width() - size.cx) / 2, (rcclip.Height()*3 - size.cy*1) / 4);
  1381. CRect rc(pt, size);
  1382. int nField = 0;
  1383. int fAligned = 1;
  1384. DWORD end[2] = {offset[1], (p[2]<<8)|p[3]};
  1385. while((nField == 0 && offset[0] < end[0]) || (nField == 1 && offset[1] < end[1]))
  1386. {
  1387. BYTE code;
  1388. if((code = GetNibble(p, offset, nField, fAligned)) >= 0x4)
  1389. {
  1390. DrawPixels(yuv, w, pt, code >> 2, m_sppal[0][code&3], rcclip);
  1391. pt.x += code >> 2;
  1392. continue;
  1393. }
  1394. code = GetNibble(p, offset, nField, fAligned);
  1395. DrawPixels(yuv, w, pt, rc.right - pt.x, m_sppal[0][code&3], rcclip);
  1396. if(!fAligned) GetNibble(p, offset, nField, fAligned); // align to byte
  1397. pt.x = rc.left;
  1398. pt.y++;
  1399. nField = 1 - nField;
  1400. }
  1401. }
  1402. // CSubpicInputPin::svcdspu
  1403. bool CSubpicInputPin::svcdspu::Parse()
  1404. {
  1405. BYTE* p = m_pData.GetData();
  1406. BYTE* p0 = p;
  1407. if(m_pData.GetSize() < 2) 
  1408. return(false);
  1409. WORD packetsize = (p[0]<<8)|p[1]; p += 2;
  1410.     if(packetsize > m_pData.GetSize())
  1411. return(false);
  1412. bool duration = !!(*p++&0x04);
  1413. *p++; // unknown
  1414. if(duration)
  1415. {
  1416. m_rtStop = m_rtStart + 10000i64*((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3])/90;
  1417. p += 4;
  1418. }
  1419. m_sphli.StartX = m_sphli.StopX = (p[0]<<8)|p[1]; p += 2;
  1420. m_sphli.StartY = m_sphli.StopY = (p[0]<<8)|p[1]; p += 2;
  1421. m_sphli.StopX += (p[0]<<8)|p[1]; p += 2;
  1422. m_sphli.StopY += (p[0]<<8)|p[1]; p += 2;
  1423. for(int i = 0; i < 4; i++)
  1424. {
  1425. m_sppal[i].Y = *p++;
  1426. m_sppal[i].U = *p++;
  1427. m_sppal[i].V = *p++;
  1428. m_sppal[i].Reserved = *p++ >> 4;
  1429. }
  1430. if(*p++&0xc0)
  1431. p += 4; // duration of the shift operation should be here, but it is untested
  1432. m_offset[1] = (p[0]<<8)|p[1]; p += 2;
  1433. m_offset[0] = p - p0;
  1434. m_offset[1] += m_offset[0];
  1435. return(true);
  1436. }
  1437. void CSubpicInputPin::svcdspu::Render(BYTE** yuv, int w, int h, AM_DVD_YUV* sppal, bool fsppal)
  1438. {
  1439. BYTE* p = m_pData.GetData();
  1440. DWORD offset[2] = {m_offset[0], m_offset[1]};
  1441. CRect rcclip(0, 0, w, h);
  1442. /* FIXME: startx/y looks to be wrong in the sample I tested (yes, this one too!)
  1443. CPoint pt(m_sphli.StartX, m_sphli.StartY);
  1444. CRect rc(pt, CPoint(m_sphli.StopX, m_sphli.StopY));
  1445. */
  1446. CSize size(m_sphli.StopX - m_sphli.StartX, m_sphli.StopY - m_sphli.StartY);
  1447. CPoint pt((rcclip.Width() - size.cx) / 2, (rcclip.Height()*3 - size.cy*1) / 4);
  1448. CRect rc(pt, size);
  1449. int nField = 0;
  1450. int n = 3;
  1451. DWORD end[2] = {offset[1], (p[2]<<8)|p[3]};
  1452. while((nField == 0 && offset[0] < end[0]) || (nField == 1 && offset[1] < end[1]))
  1453. {
  1454. BYTE code = GetHalfNibble(p, offset, nField, n);
  1455. BYTE repeat = 1 + (code == 0 ? GetHalfNibble(p, offset, nField, n) : 0);
  1456. DrawPixels(yuv, w, pt, repeat, m_sppal[code&3], rcclip);
  1457. if((pt.x += repeat) < rc.right) continue;
  1458. while(n != 3)
  1459. GetHalfNibble(p, offset, nField, n); // align to byte
  1460. pt.x = rc.left;
  1461. pt.y++;
  1462. nField = 1 - nField;
  1463. }
  1464. }
  1465. //
  1466. // CClosedCaptionOutputPin
  1467. //
  1468. CClosedCaptionOutputPin::CClosedCaptionOutputPin(CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  1469. : CBaseOutputPin(NAME("CClosedCaptionOutputPin"), pFilter, pLock, phr, L"~CC")
  1470. {
  1471. }
  1472. HRESULT CClosedCaptionOutputPin::CheckMediaType(const CMediaType* mtOut)
  1473. {
  1474. return mtOut->majortype == MEDIATYPE_AUXLine21Data && mtOut->subtype == MEDIASUBTYPE_Line21_GOPPacket
  1475. ? S_OK
  1476. : VFW_E_TYPE_NOT_ACCEPTED;
  1477. }
  1478. HRESULT CClosedCaptionOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
  1479. {
  1480. if(iPosition < 0) return E_INVALIDARG;
  1481. if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
  1482. pmt->InitMediaType();
  1483. pmt->majortype = MEDIATYPE_AUXLine21Data;
  1484. pmt->subtype = MEDIASUBTYPE_Line21_GOPPacket;
  1485. pmt->formattype = FORMAT_None;
  1486. return S_OK;
  1487. }
  1488. HRESULT CClosedCaptionOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
  1489. {
  1490. pProperties->cBuffers = 1;
  1491. pProperties->cbBuffer = 2048;
  1492. pProperties->cbAlign = 1;
  1493. pProperties->cbPrefix = 0;
  1494. HRESULT hr;
  1495. ALLOCATOR_PROPERTIES Actual;
  1496.     if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) 
  1497. return hr;
  1498.     return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
  1499. ? E_FAIL
  1500. : NOERROR;
  1501. }