Add colour space auto guess option to UI.
[xy_vsfilter.git] / src / filters / transform / vsfilter / Copy.cpp
blobe772309bef5a3a50f3e4a0d846bd17e5516a7e9b
1 // Copyright 2003-2006 Gabest
2 // http://www.gabest.org
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html
19 #include "stdafx.h"
20 #include <math.h>
21 #include "DirectVobSubFilter.h"
22 #include "..\..\..\DSUtil\DSUtil.h"
23 #include "..\..\..\DSUtil\MediaTypes.h"
25 #include <initguid.h>
26 #include "../../../../include/moreuuids.h"
27 #include "../../subpic/color_conv_table.h"
29 #include "xy_logger.h"
31 static void LogSubPicStartStop( const REFERENCE_TIME& rtStart, const REFERENCE_TIME& rtStop, const CString& msg)
33 #ifdef __DO_LOG
34 static REFERENCE_TIME s_rtStart = -1, s_rtStop = -1;
35 if(s_rtStart!=rtStart || s_rtStop!=rtStop)
37 XY_LOG_INFO(msg.GetString());
38 s_rtStart=rtStart;
39 s_rtStop=rtStop;
41 #endif
44 void BltLineRGB32(DWORD* d, BYTE* sub, int w, const GUID& subtype)
46 const ColorConvTable* color_conv_table = ColorConvTable::GetDefaultColorConvTable();
47 if(subtype == MEDIASUBTYPE_YV12 || subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV)
49 //TODO: Fix ME!
50 BYTE* db = (BYTE*)d;
51 BYTE* dbtend = db + w;
53 for(; db < dbtend; sub+=4, db++)
55 if(sub[3] < 0xff)
57 int y = (color_conv_table->c2y_yb[sub[0]] + color_conv_table->c2y_yg[sub[1]] + color_conv_table->c2y_yr[sub[2]] + 0x108000) >> 16;
58 *db = y; // w/o colors
62 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
64 //TODO: Fix ME!
65 WORD* db = reinterpret_cast<WORD*>(d);
66 WORD* dbtend = db + w;
68 for(; db < dbtend; sub+=4, db++)
70 if(sub[3] < 0xff)
72 int y = (color_conv_table->c2y_yb[sub[0]] + color_conv_table->c2y_yg[sub[1]] + color_conv_table->c2y_yr[sub[2]] + 0x108000) >> 14;
73 *db = y; // w/o colors
77 else if(subtype == MEDIASUBTYPE_YUY2)
79 WORD* ds = (WORD*)d;
80 WORD* dstend = ds + w;
82 for(; ds < dstend; sub+=4, ds++)
84 if(sub[3] < 0xff)
86 int y = (color_conv_table->c2y_yb[sub[0]] + color_conv_table->c2y_yg[sub[1]] + color_conv_table->c2y_yr[sub[2]] + 0x108000) >> 16;
87 *ds = 0x8000|y; // w/o colors
91 else if(subtype == MEDIASUBTYPE_RGB555)
93 WORD* ds = (WORD*)d;
94 WORD* dstend = ds + w;
96 for(; ds < dstend; sub+=4, ds++)
98 if(sub[3] < 0xff)
100 *ds = ((*((DWORD*)sub)>>9)&0x7c00)|((*((DWORD*)sub)>>6)&0x03e0)|((*((DWORD*)sub)>>3)&0x001f);
104 else if(subtype == MEDIASUBTYPE_RGB565)
106 WORD* ds = (WORD*)d;
107 WORD* dstend = ds + w;
109 for(; ds < dstend; sub+=4, ds++)
111 if(sub[3] < 0xff)
113 *ds = ((*((DWORD*)sub)>>8)&0xf800)|((*((DWORD*)sub)>>5)&0x07e0)|((*((DWORD*)sub)>>3)&0x001f);
117 else if(subtype == MEDIASUBTYPE_RGB24)
119 BYTE* dt = (BYTE*)d;
120 BYTE* dstend = dt + w*3;
122 for(; dt < dstend; sub+=4, dt+=3)
124 if(sub[3] < 0xff)
126 dt[0] = sub[0];
127 dt[1] = sub[1];
128 dt[2] = sub[2];
132 else if(subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_ARGB32)
134 DWORD* dstend = d + w;
136 for(; d < dstend; sub+=4, d++)
138 if(sub[3] < 0xff) *d = *((DWORD*)sub)&0xffffff;
143 /* ResX2 */
144 void Scale2x(const GUID& subtype, BYTE* d, int dpitch, BYTE* s, int spitch, int w, int h)
146 if(subtype == MEDIASUBTYPE_YV12 || subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV)
148 BYTE* s1;
149 BYTE* s2;
150 BYTE* d1;
152 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
154 BYTE* stmp = s1 + spitch;
155 BYTE* dtmp = d1 + dpitch;
157 for(BYTE* s3 = s1 + (w-1); s1 < s3; s1 += 1, d1 += 2)
159 d1[0] = s1[0];
160 d1[1] = (s1[0]+s1[1])>>1;
163 d1[0] = d1[1] = s1[0];
165 s1 += 1;
166 d1 += 2;
168 s1 = stmp;
169 d1 = dtmp;
172 AvgLines8(d, h*2, dpitch);
174 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
176 BYTE* s1 = s;
177 BYTE* s1_end = s + h*spitch;
178 BYTE* d1 = d;
180 for( ; s1 < s1_end; s1 += spitch, d1 += dpitch )
182 WORD* s2 = reinterpret_cast<WORD*>(s1);
183 WORD* s2_end = reinterpret_cast<WORD*>(s1) + (w-1);
184 WORD* d2 = reinterpret_cast<WORD*>(d1);
186 for( ; s2 < s2_end; s2 ++, d2 += 2)
188 d2[0] = s2[0];
189 d2[1] = (s2[0]+s2[1])>>1;
191 d2[0] = d2[1] = s1[0];
194 AvgLines8(d, h*2, dpitch);
196 else if(subtype == MEDIASUBTYPE_YUY2)
198 unsigned __int64 __0xffffffff00000000 = 0xffffffff00000000;
199 unsigned __int64 __0x00000000ffffffff = 0x00000000ffffffff;
200 unsigned __int64 __0x00ff00ff00ff00ff = 0x00ff00ff00ff00ff;
202 BYTE* s1;
203 BYTE* s2;
204 BYTE* d1;
206 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch)
208 BYTE* stmp = s1 + spitch;
209 BYTE* dtmp = d1 + dpitch;
211 // row0, 4 pixels: y1|u1|y2|v1|y3|u2|y4|v2
212 // ->
213 // row0, 8 pixels: y1|u1|(y1+y2)/2|v1|y2|(u1+u2)/2|(y2+y3)/2|(v1+v2)/2
215 __asm
217 mov esi, s1
218 mov edi, d1
220 mov ecx, w
221 shr ecx, 1
222 dec ecx
224 movq mm4, __0x00ff00ff00ff00ff
225 movq mm5, __0x00000000ffffffff
226 movq mm6, __0xffffffff00000000
227 row_loop1:
228 movq mm0, [esi]
229 movq mm2, mm0
231 pand mm0, mm4 // mm0 = 00y400y300y200y1
232 psrlw mm2, 8 // mm2 = 00u200v200u100v1
235 movq mm1, mm0
237 pand mm0, mm5 // mm0 = 0000000000y200y1
239 psllq mm1, 16
240 pand mm1, mm6 // mm1 = 00y300y200000000
242 por mm1, mm0 // mm1 = 00y300y200y200y1
244 punpcklwd mm0, mm0 // mm0 = 00y200y200y100y1
246 paddw mm0, mm1
247 psrlw mm0, 1 // mm0 = (mm0 + mm1) / 2
250 movq mm1, mm2
251 punpckldq mm1, mm1 // mm1 = 00u100v100u100v1
253 paddw mm1, mm2
254 psrlw mm1, 1 // mm1 = (mm1 + mm2) / 2
257 psllw mm1, 8
258 por mm0, mm1 // mm0 = (v1+v2)/2|(y2+y3)/2|(u1+u2)/2|y2|v1|(y1+y2)/2|u1|y1
260 movq [edi], mm0
262 lea esi, [esi+4]
263 lea edi, [edi+8]
265 dec ecx
266 jnz row_loop1
268 mov s1, esi
269 mov d1, edi
272 *d1++ = s1[0];
273 *d1++ = s1[1];
274 *d1++ =(s1[0]+s1[2])>>1;
275 *d1++ = s1[3];
277 *d1++ = s1[2];
278 *d1++ = s1[1];
279 *d1++ = s1[2];
280 *d1++ = s1[3];
282 s1 += 4;
284 s1 = stmp;
285 d1 = dtmp;
288 AvgLines8(d, h*2, dpitch);
290 else if(subtype == MEDIASUBTYPE_RGB555)
292 BYTE* s1;
293 BYTE* s2;
294 BYTE* d1;
296 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
298 BYTE* stmp = s1 + spitch;
299 BYTE* dtmp = d1 + dpitch;
301 for(BYTE* s3 = s1 + (w-1)*2; s1 < s3; s1 += 2, d1 += 4)
303 *((WORD*)d1) = *((WORD*)s1);
304 *((WORD*)d1+1) =
305 ((((*((WORD*)s1)&0x7c00) + (*((WORD*)s1+1)&0x7c00)) >> 1)&0x7c00)|
306 ((((*((WORD*)s1)&0x03e0) + (*((WORD*)s1+1)&0x03e0)) >> 1)&0x03e0)|
307 ((((*((WORD*)s1)&0x001f) + (*((WORD*)s1+1)&0x001f)) >> 1)&0x001f);
310 *((WORD*)d1) = *((WORD*)s1);
311 *((WORD*)d1+1) = *((WORD*)s1);
313 s1 += 2;
314 d1 += 4;
316 s1 = stmp;
317 d1 = dtmp;
320 AvgLines555(d, h*2, dpitch);
322 else if(subtype == MEDIASUBTYPE_RGB565)
324 BYTE* s1;
325 BYTE* s2;
326 BYTE* d1;
328 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
330 BYTE* stmp = s1 + spitch;
331 BYTE* dtmp = d1 + dpitch;
333 for(BYTE* s3 = s1 + (w-1)*2; s1 < s3; s1 += 2, d1 += 4)
335 *((WORD*)d1) = *((WORD*)s1);
336 *((WORD*)d1+1) =
337 ((((*((WORD*)s1)&0xf800) + (*((WORD*)s1+1)&0xf800)) >> 1)&0xf800)|
338 ((((*((WORD*)s1)&0x07e0) + (*((WORD*)s1+1)&0x07e0)) >> 1)&0x07e0)|
339 ((((*((WORD*)s1)&0x001f) + (*((WORD*)s1+1)&0x001f)) >> 1)&0x001f);
342 *((WORD*)d1) = *((WORD*)s1);
343 *((WORD*)d1+1) = *((WORD*)s1);
345 s1 += 2;
346 d1 += 4;
348 s1 = stmp;
349 d1 = dtmp;
352 AvgLines565(d, h*2, dpitch);
354 else if(subtype == MEDIASUBTYPE_RGB24)
356 BYTE* s1;
357 BYTE* s2;
358 BYTE* d1;
360 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
362 BYTE* stmp = s1 + spitch;
363 BYTE* dtmp = d1 + dpitch;
365 for(BYTE* s3 = s1 + (w-1)*3; s1 < s3; s1 += 3, d1 += 6)
367 d1[0] = s1[0];
368 d1[1] = s1[1];
369 d1[2] = s1[2];
370 d1[3] = (s1[0]+s1[3])>>1;
371 d1[4] = (s1[1]+s1[4])>>1;
372 d1[5] = (s1[2]+s1[5])>>1;
375 d1[0] = d1[3] = s1[0];
376 d1[1] = d1[4] = s1[1];
377 d1[2] = d1[5] = s1[2];
379 s1 += 3;
380 d1 += 6;
382 s1 = stmp;
383 d1 = dtmp;
386 AvgLines8(d, h*2, dpitch);
388 else if(subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_ARGB32)
390 BYTE* s1;
391 BYTE* s2;
392 BYTE* d1;
394 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch)
396 BYTE* stmp = s1 + spitch;
397 BYTE* dtmp = d1 + dpitch;
399 __asm
401 mov esi, s1
402 mov edi, d1
404 mov ecx, w
405 dec ecx
407 pxor mm0, mm0
408 row_loop3:
409 movq mm1, [esi]
410 movq mm2, mm1
412 punpcklbw mm1, mm0 // mm1 = 00xx00r100g100b1
413 punpckhbw mm2, mm0 // mm2 = 00xx00r200g200b2
415 paddw mm2, mm1
416 psrlw mm2, 1 // mm2 = (mm1 + mm2) / 2
418 packuswb mm1, mm2
420 movq [edi], mm1
422 lea esi, [esi+4]
423 lea edi, [edi+8]
425 dec ecx
426 jnz row_loop3
428 mov s1, esi
429 mov d1, edi
432 *((DWORD*)d1) = *((DWORD*)s1);
433 *((DWORD*)d1+1) = *((DWORD*)s1);
435 s1 += 4;
436 d1 += 8;
438 s1 = stmp;
439 d1 = dtmp;
442 AvgLines8(d, h*2, dpitch);
445 __asm emms;
448 HRESULT Copy(BYTE* pSub, BYTE* pIn, CSize sub, CSize in, int bpp, const GUID& subtype, DWORD black)
450 int wIn = in.cx, hIn = in.cy, pitchIn = wIn*bpp>>3;
451 int wSub = sub.cx, hSub = sub.cy, pitchSub = wSub*bpp>>3;
452 bool fScale2x = wIn*2 <= wSub;
454 if(fScale2x) wIn <<= 1, hIn <<= 1;
456 int left = ((wSub - wIn)>>1)&~1;
457 int mid = wIn;
458 int right = left + ((wSub - wIn)&1);
460 int dpLeft = left*bpp>>3;
461 int dpMid = mid*bpp>>3;
462 int dpRight = right*bpp>>3;
464 ASSERT(wSub >= wIn);
467 int i = 0, j = 0;
469 j += (hSub - hIn) >> 1;
471 for(; i < j; i++, pSub += pitchSub)
473 memsetd(pSub, black, dpLeft+dpMid+dpRight);
476 j += hIn;
478 if(hIn > hSub)
479 pIn += pitchIn * ((hIn - hSub) >> (fScale2x?2:1));
481 if(fScale2x)
483 Scale2x(subtype,
484 pSub + dpLeft, pitchSub, pIn, pitchIn,
485 in.cx, (min(j, hSub) - i) >> 1);
487 for(int k = min(j, hSub); i < k; i++, pIn += pitchIn, pSub += pitchSub)
489 memsetd(pSub, black, dpLeft);
490 memsetd(pSub + dpLeft+dpMid, black, dpRight);
493 else
495 for(int k = min(j, hSub); i < k; i++, pIn += pitchIn, pSub += pitchSub)
497 memsetd(pSub, black, dpLeft);
498 memcpy(pSub + dpLeft, pIn, dpMid);
499 memsetd(pSub + dpLeft+dpMid, black, dpRight);
503 j = hSub;
505 for(; i < j; i++, pSub += pitchSub)
507 memsetd(pSub, black, dpLeft+dpMid+dpRight);
511 return NOERROR;
514 HRESULT CDirectVobSubFilter::Copy(BYTE* pSub, BYTE* pIn, CSize sub, CSize in, int bpp, const GUID& subtype, DWORD black)
516 return ::Copy(pSub, pIn, sub, in, bpp, subtype, black);
519 void CDirectVobSubFilter::PrintMessages(BYTE* pOut)
521 if(!m_hdc || !m_hbm)
522 return;
524 const GUID& subtype = m_pOutput->CurrentMediaType().subtype;
526 BITMAPINFOHEADER bihOut;
527 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
529 CString msg, tmp;
531 if(m_fOSD)
533 tmp.Format(_T("in: %dx%d %s\nout: %dx%d %s\n"),
534 m_w, m_h,
535 Subtype2String(m_pInput->CurrentMediaType().subtype),
536 bihOut.biWidth, bihOut.biHeight,
537 Subtype2String(m_pOutput->CurrentMediaType().subtype));
538 msg += tmp;
540 tmp.Format(_T("real fps: %.3f, current fps: %.3f\nmedia time: %d, subtitle time: %d [ms]\nframe number: %d (calculated)\nrate: %.4f\n"),
541 m_fps, m_fMediaFPSEnabled?m_MediaFPS:fabs(m_fps),
542 (int)m_tPrev.Millisecs(), (int)(CalcCurrentTime()/10000),
543 (int)(m_tPrev.m_time * m_fps / 10000000),
544 m_pInput->CurrentRate());
545 msg += tmp;
547 CAutoLock cAutoLock(&m_csQueueLock);
549 if(m_pSubPicQueue)
551 int nSubPics = -1;
552 REFERENCE_TIME rtNow = -1, rtStart = -1, rtStop = -1;
553 m_pSubPicQueue->GetStats(nSubPics, rtNow, rtStart, rtStop);
554 tmp.Format(_T("queue stats: %I64d - %I64d [ms]\n"), rtStart/10000, rtStop/10000);
555 msg += tmp;
557 for(int i = 0; i < nSubPics; i++)
559 m_pSubPicQueue->GetStats(i, rtStart, rtStop);
560 tmp.Format(_T("%d: %I64d - %I64d [ms]\n"), i, rtStart/10000, rtStop/10000);
561 msg += tmp;
563 LogSubPicStartStop(rtStart, rtStop, tmp);
566 //colour space
567 tmp.Format( _T("Colourspace: %ls (%ls)\n"),
568 ColorConvTable::GetDefaultYUVType()==ColorConvTable::BT601 ? _T("BT.601"):_T("BT.709"),
569 m_colourSpace==CDirectVobSub::AUTO_GUESS ? _T("Guessed") : _T("forced") );
570 msg += tmp;
572 //print cache info
573 CachesInfo caches_info;
574 get_CachesInfo(&caches_info);
575 tmp.Format(
576 _T("Cache :stored_num/hit_count/query_count\n")\
577 _T(" Parser cache 1:%ld/%ld/%ld\n")\
578 _T(" Parser cache 2:%ld/%ld/%ld\n")\
579 _T("\n")\
580 _T(" LV 4:%ld/%ld/%ld\n")\
581 _T(" LV 3:%ld/%ld/%ld\n")\
582 _T(" LV 2:%ld/%ld/%ld\n")\
583 _T(" LV 1:%ld/%ld/%ld\n")\
584 _T(" LV 0:%ld/%ld/%ld\n"),
585 caches_info.text_info_cache_cur_item_num, caches_info.text_info_cache_hit_count, caches_info.text_info_cache_query_count,
586 caches_info.word_info_cache_cur_item_num, caches_info.word_info_cache_hit_count, caches_info.word_info_cache_query_count,
587 caches_info.path_cache_cur_item_num, caches_info.path_cache_hit_count, caches_info.path_cache_query_count,
588 caches_info.scanline_cache_cur_item_num, caches_info.scanline_cache_hit_count, caches_info.scanline_cache_query_count,
589 caches_info.non_blur_cache_cur_item_num, caches_info.non_blur_cache_hit_count, caches_info.non_blur_cache_query_count,
590 caches_info.overlay_cache_cur_item_num, caches_info.overlay_cache_hit_count, caches_info.overlay_cache_query_count,
591 caches_info.interpolate_cache_cur_item_num, caches_info.interpolate_cache_hit_count, caches_info.interpolate_cache_query_count);
592 msg += tmp;
595 if(msg.IsEmpty()) return;
597 HANDLE hOldBitmap = SelectObject(m_hdc, m_hbm);
598 HANDLE hOldFont = SelectObject(m_hdc, m_hfont);
600 SetTextColor(m_hdc, 0xffffff);
601 SetBkMode(m_hdc, TRANSPARENT);
602 SetMapMode(m_hdc, MM_TEXT);
604 BITMAP bm;
605 GetObject(m_hbm, sizeof(BITMAP), &bm);
607 CRect r(0, 0, bm.bmWidth, bm.bmHeight);
608 DrawText(m_hdc, msg, _tcslen(msg), &r, DT_CALCRECT|DT_EXTERNALLEADING|DT_NOPREFIX|DT_WORDBREAK);
610 r += CPoint(10, 10);
611 r &= CRect(0, 0, bm.bmWidth, bm.bmHeight);
613 DrawText(m_hdc, msg, _tcslen(msg), &r, DT_LEFT|DT_TOP|DT_NOPREFIX|DT_WORDBREAK);
615 BYTE* pIn = (BYTE*)bm.bmBits;
616 int pitchIn = bm.bmWidthBytes;
617 int pitchOut = bihOut.biWidth * bihOut.biBitCount >> 3;
619 if(subtype == MEDIASUBTYPE_YV12 || subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV)
620 pitchOut = bihOut.biWidth;
621 else if (subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
622 pitchOut = bihOut.biWidth * 2;
624 pitchIn = (pitchIn+3)&~3;
625 pitchOut = (pitchOut+3)&~3;
627 if(bihOut.biHeight > 0 && bihOut.biCompression <= 3) // flip if the dst bitmap is flipped rgb (m_hbm is a top-down bitmap, not like the subpictures)
629 pOut += pitchOut * (abs(bihOut.biHeight)-1);
630 pitchOut = -pitchOut;
633 pIn += pitchIn * r.top;
634 pOut += pitchOut * r.top;
636 for(int w = min(r.right, m_w), h = r.Height(); h--; pIn += pitchIn, pOut += pitchOut)
638 BltLineRGB32((DWORD*)pOut, pIn, w, subtype);
639 memsetd(pIn, 0xff000000, r.right*4);
642 SelectObject(m_hdc, hOldBitmap);
643 SelectObject(m_hdc, hOldFont);