1 // Copyright 2003-2006 Gabest
2 // http://www.gabest.org
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.
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
21 #include "DirectVobSubFilter.h"
22 #include "..\..\..\DSUtil\DSUtil.h"
23 #include "..\..\..\DSUtil\MediaTypes.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
)
34 static REFERENCE_TIME s_rtStart
= -1, s_rtStop
= -1;
35 if(s_rtStart
!=rtStart
|| s_rtStop
!=rtStop
)
37 XY_LOG_INFO(msg
.GetString());
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
)
51 BYTE
* dbtend
= db
+ w
;
53 for(; db
< dbtend
; sub
+=4, db
++)
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
)
65 WORD
* db
= reinterpret_cast<WORD
*>(d
);
66 WORD
* dbtend
= db
+ w
;
68 for(; db
< dbtend
; sub
+=4, db
++)
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
)
80 WORD
* dstend
= ds
+ w
;
82 for(; ds
< dstend
; sub
+=4, ds
++)
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
)
94 WORD
* dstend
= ds
+ w
;
96 for(; ds
< dstend
; sub
+=4, ds
++)
100 *ds
= ((*((DWORD
*)sub
)>>9)&0x7c00)|((*((DWORD
*)sub
)>>6)&0x03e0)|((*((DWORD
*)sub
)>>3)&0x001f);
104 else if(subtype
== MEDIASUBTYPE_RGB565
)
107 WORD
* dstend
= ds
+ w
;
109 for(; ds
< dstend
; sub
+=4, ds
++)
113 *ds
= ((*((DWORD
*)sub
)>>8)&0xf800)|((*((DWORD
*)sub
)>>5)&0x07e0)|((*((DWORD
*)sub
)>>3)&0x001f);
117 else if(subtype
== MEDIASUBTYPE_RGB24
)
120 BYTE
* dstend
= dt
+ w
*3;
122 for(; dt
< dstend
; sub
+=4, dt
+=3)
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;
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
)
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)
160 d1
[1] = (s1
[0]+s1
[1])>>1;
163 d1
[0] = d1
[1] = s1
[0];
172 AvgLines8(d
, h
*2, dpitch
);
174 else if(subtype
== MEDIASUBTYPE_P010
|| subtype
== MEDIASUBTYPE_P016
)
177 BYTE
* s1_end
= s
+ h
*spitch
;
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)
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;
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
213 // row0, 8 pixels: y1|u1|(y1+y2)/2|v1|y2|(u1+u2)/2|(y2+y3)/2|(v1+v2)/2
224 movq mm4
, __0x00ff00ff00ff00ff
225 movq mm5
, __0x00000000ffffffff
226 movq mm6
, __0xffffffff00000000
231 pand mm0
, mm4
// mm0 = 00y400y300y200y1
232 psrlw mm2
, 8 // mm2 = 00u200v200u100v1
237 pand mm0
, mm5
// mm0 = 0000000000y200y1
240 pand mm1
, mm6
// mm1 = 00y300y200000000
242 por mm1
, mm0
// mm1 = 00y300y200y200y1
244 punpcklwd mm0
, mm0
// mm0 = 00y200y200y100y1
247 psrlw mm0
, 1 // mm0 = (mm0 + mm1) / 2
251 punpckldq mm1
, mm1
// mm1 = 00u100v100u100v1
254 psrlw mm1
, 1 // mm1 = (mm1 + mm2) / 2
258 por mm0
, mm1
// mm0 = (v1+v2)/2|(y2+y3)/2|(u1+u2)/2|y2|v1|(y1+y2)/2|u1|y1
274 *d1
++ =(s1
[0]+s1
[2])>>1;
288 AvgLines8(d
, h
*2, dpitch
);
290 else if(subtype
== MEDIASUBTYPE_RGB555
)
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
);
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
);
320 AvgLines555(d
, h
*2, dpitch
);
322 else if(subtype
== MEDIASUBTYPE_RGB565
)
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
);
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
);
352 AvgLines565(d
, h
*2, dpitch
);
354 else if(subtype
== MEDIASUBTYPE_RGB24
)
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)
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];
386 AvgLines8(d
, h
*2, dpitch
);
388 else if(subtype
== MEDIASUBTYPE_RGB32
|| subtype
== MEDIASUBTYPE_ARGB32
)
394 for(s1
= s
, s2
= s
+ h
*spitch
, d1
= d
; s1
< s2
; d1
+= dpitch
)
396 BYTE
* stmp
= s1
+ spitch
;
397 BYTE
* dtmp
= d1
+ dpitch
;
412 punpcklbw mm1
, mm0
// mm1 = 00xx00r100g100b1
413 punpckhbw mm2
, mm0
// mm2 = 00xx00r200g200b2
416 psrlw mm2
, 1 // mm2 = (mm1 + mm2) / 2
432 *((DWORD
*)d1
) = *((DWORD
*)s1
);
433 *((DWORD
*)d1
+1) = *((DWORD
*)s1
);
442 AvgLines8(d
, h
*2, dpitch
);
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;
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;
469 j
+= (hSub
- hIn
) >> 1;
471 for(; i
< j
; i
++, pSub
+= pitchSub
)
473 memsetd(pSub
, black
, dpLeft
+dpMid
+dpRight
);
479 pIn
+= pitchIn
* ((hIn
- hSub
) >> (fScale2x
?2:1));
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
);
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
);
505 for(; i
< j
; i
++, pSub
+= pitchSub
)
507 memsetd(pSub
, black
, dpLeft
+dpMid
+dpRight
);
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
)
524 const GUID
& subtype
= m_pOutput
->CurrentMediaType().subtype
;
526 BITMAPINFOHEADER bihOut
;
527 ExtractBIH(&m_pOutput
->CurrentMediaType(), &bihOut
);
533 tmp
.Format(_T("in: %dx%d %s\nout: %dx%d %s\n"),
535 Subtype2String(m_pInput
->CurrentMediaType().subtype
),
536 bihOut
.biWidth
, bihOut
.biHeight
,
537 Subtype2String(m_pOutput
->CurrentMediaType().subtype
));
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());
547 CAutoLock
cAutoLock(&m_csQueueLock
);
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);
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);
563 LogSubPicStartStop(rtStart
, rtStop
, tmp
);
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") );
573 CachesInfo caches_info
;
574 get_CachesInfo(&caches_info
);
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")\
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
);
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
);
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
);
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
);