Fix naming.
[xy_vsfilter.git] / src / filters / transform / vsfilter / Copy.cpp
blobaa43731c14b082000b73366a0ccda0ffb7da8abf
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 using namespace DirectVobSubXyOptions;
33 static void LogSubPicStartStop( const REFERENCE_TIME& rtStart, const REFERENCE_TIME& rtStop, const CString& msg)
35 #ifdef __DO_LOG
36 static REFERENCE_TIME s_rtStart = -1, s_rtStop = -1;
37 if(s_rtStart!=rtStart || s_rtStop!=rtStop)
39 XY_LOG_INFO(msg.GetString());
40 s_rtStart=rtStart;
41 s_rtStop=rtStop;
43 #endif
46 void BltLineRGB32(DWORD* d, BYTE* sub, int w, const GUID& subtype)
48 if(subtype == MEDIASUBTYPE_YV12 || subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV
49 || subtype == MEDIASUBTYPE_NV12 || subtype == MEDIASUBTYPE_NV21)
51 //TODO: Fix ME!
52 BYTE* db = (BYTE*)d;
53 BYTE* dbtend = db + w;
55 for(; db < dbtend; sub+=4, db++)
57 if(sub[3] < 0xff)
59 int y = ColorConvTable::Rgb2Y(sub[2], sub[1], sub[0]);
60 *db = y; // w/o colors
64 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
66 //TODO: Fix ME!
67 WORD* db = reinterpret_cast<WORD*>(d);
68 WORD* dbtend = db + w;
70 for(; db < dbtend; sub+=4, db++)
72 if(sub[3] < 0xff)
74 int y = ColorConvTable::Rgb2Y(sub[2], sub[1], sub[0])<<2;
75 *db = y<<8; // w/o colors
79 else if(subtype == MEDIASUBTYPE_YUY2)
81 WORD* ds = (WORD*)d;
82 WORD* dstend = ds + w;
84 for(; ds < dstend; sub+=4, ds++)
86 if(sub[3] < 0xff)
88 int y = ColorConvTable::Rgb2Y(sub[2], sub[1], sub[0]);
89 *ds = 0x8000|y; // w/o colors
93 else if(subtype == MEDIASUBTYPE_RGB555)
95 WORD* ds = (WORD*)d;
96 WORD* dstend = ds + w;
98 for(; ds < dstend; sub+=4, ds++)
100 if(sub[3] < 0xff)
102 *ds = ((*((DWORD*)sub)>>9)&0x7c00)|((*((DWORD*)sub)>>6)&0x03e0)|((*((DWORD*)sub)>>3)&0x001f);
106 else if(subtype == MEDIASUBTYPE_RGB565)
108 WORD* ds = (WORD*)d;
109 WORD* dstend = ds + w;
111 for(; ds < dstend; sub+=4, ds++)
113 if(sub[3] < 0xff)
115 *ds = ((*((DWORD*)sub)>>8)&0xf800)|((*((DWORD*)sub)>>5)&0x07e0)|((*((DWORD*)sub)>>3)&0x001f);
119 else if(subtype == MEDIASUBTYPE_RGB24)
121 BYTE* dt = (BYTE*)d;
122 BYTE* dstend = dt + w*3;
124 for(; dt < dstend; sub+=4, dt+=3)
126 if(sub[3] < 0xff)
128 dt[0] = sub[0];
129 dt[1] = sub[1];
130 dt[2] = sub[2];
134 else if(subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_ARGB32)
136 DWORD* dstend = d + w;
138 for(; d < dstend; sub+=4, d++)
140 if(sub[3] < 0xff) *d = *((DWORD*)sub)&0xffffff;
145 /* ResX2 */
146 void Scale2x(const GUID& subtype, BYTE* d, int dpitch, BYTE* s, int spitch, int w, int h)
148 if(subtype == MEDIASUBTYPE_YV12 || subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV
149 || subtype == MEDIASUBTYPE_NV12 || subtype == MEDIASUBTYPE_NV21)
151 BYTE* s1;
152 BYTE* s2;
153 BYTE* d1;
155 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
157 BYTE* stmp = s1 + spitch;
158 BYTE* dtmp = d1 + dpitch;
160 for(BYTE* s3 = s1 + (w-1); s1 < s3; s1 += 1, d1 += 2)
162 d1[0] = s1[0];
163 d1[1] = (s1[0]+s1[1])>>1;
166 d1[0] = d1[1] = s1[0];
168 s1 += 1;
169 d1 += 2;
171 s1 = stmp;
172 d1 = dtmp;
175 AvgLines8(d, h*2, dpitch);
177 else if(subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
179 BYTE* s1 = s;
180 BYTE* s1_end = s + h*spitch;
181 BYTE* d1 = d;
183 for( ; s1 < s1_end; s1 += spitch, d1 += dpitch )
185 WORD* s2 = reinterpret_cast<WORD*>(s1);
186 WORD* s2_end = reinterpret_cast<WORD*>(s1) + (w-1);
187 WORD* d2 = reinterpret_cast<WORD*>(d1);
189 for( ; s2 < s2_end; s2 ++, d2 += 2)
191 d2[0] = s2[0];
192 d2[1] = (s2[0]+s2[1])>>1;
194 d2[0] = d2[1] = s1[0];
197 AvgLines8(d, h*2, dpitch);
199 else if(subtype == MEDIASUBTYPE_YUY2)
201 unsigned __int64 __0xffffffff00000000 = 0xffffffff00000000;
202 unsigned __int64 __0x00000000ffffffff = 0x00000000ffffffff;
203 unsigned __int64 __0x00ff00ff00ff00ff = 0x00ff00ff00ff00ff;
205 BYTE* s1;
206 BYTE* s2;
207 BYTE* d1;
209 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch)
211 BYTE* stmp = s1 + spitch;
212 BYTE* dtmp = d1 + dpitch;
214 // row0, 4 pixels: y1|u1|y2|v1|y3|u2|y4|v2
215 // ->
216 // row0, 8 pixels: y1|u1|(y1+y2)/2|v1|y2|(u1+u2)/2|(y2+y3)/2|(v1+v2)/2
218 __asm
220 mov esi, s1
221 mov edi, d1
223 mov ecx, w
224 shr ecx, 1
225 dec ecx
227 movq mm4, __0x00ff00ff00ff00ff
228 movq mm5, __0x00000000ffffffff
229 movq mm6, __0xffffffff00000000
230 row_loop1:
231 movq mm0, [esi]
232 movq mm2, mm0
234 pand mm0, mm4 // mm0 = 00y400y300y200y1
235 psrlw mm2, 8 // mm2 = 00u200v200u100v1
238 movq mm1, mm0
240 pand mm0, mm5 // mm0 = 0000000000y200y1
242 psllq mm1, 16
243 pand mm1, mm6 // mm1 = 00y300y200000000
245 por mm1, mm0 // mm1 = 00y300y200y200y1
247 punpcklwd mm0, mm0 // mm0 = 00y200y200y100y1
249 paddw mm0, mm1
250 psrlw mm0, 1 // mm0 = (mm0 + mm1) / 2
253 movq mm1, mm2
254 punpckldq mm1, mm1 // mm1 = 00u100v100u100v1
256 paddw mm1, mm2
257 psrlw mm1, 1 // mm1 = (mm1 + mm2) / 2
260 psllw mm1, 8
261 por mm0, mm1 // mm0 = (v1+v2)/2|(y2+y3)/2|(u1+u2)/2|y2|v1|(y1+y2)/2|u1|y1
263 movq [edi], mm0
265 lea esi, [esi+4]
266 lea edi, [edi+8]
268 dec ecx
269 jnz row_loop1
271 mov s1, esi
272 mov d1, edi
275 *d1++ = s1[0];
276 *d1++ = s1[1];
277 *d1++ =(s1[0]+s1[2])>>1;
278 *d1++ = s1[3];
280 *d1++ = s1[2];
281 *d1++ = s1[1];
282 *d1++ = s1[2];
283 *d1++ = s1[3];
285 s1 += 4;
287 s1 = stmp;
288 d1 = dtmp;
291 AvgLines8(d, h*2, dpitch);
293 else if(subtype == MEDIASUBTYPE_RGB555)
295 BYTE* s1;
296 BYTE* s2;
297 BYTE* d1;
299 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
301 BYTE* stmp = s1 + spitch;
302 BYTE* dtmp = d1 + dpitch;
304 for(BYTE* s3 = s1 + (w-1)*2; s1 < s3; s1 += 2, d1 += 4)
306 *((WORD*)d1) = *((WORD*)s1);
307 *((WORD*)d1+1) =
308 ((((*((WORD*)s1)&0x7c00) + (*((WORD*)s1+1)&0x7c00)) >> 1)&0x7c00)|
309 ((((*((WORD*)s1)&0x03e0) + (*((WORD*)s1+1)&0x03e0)) >> 1)&0x03e0)|
310 ((((*((WORD*)s1)&0x001f) + (*((WORD*)s1+1)&0x001f)) >> 1)&0x001f);
313 *((WORD*)d1) = *((WORD*)s1);
314 *((WORD*)d1+1) = *((WORD*)s1);
316 s1 += 2;
317 d1 += 4;
319 s1 = stmp;
320 d1 = dtmp;
323 AvgLines555(d, h*2, dpitch);
325 else if(subtype == MEDIASUBTYPE_RGB565)
327 BYTE* s1;
328 BYTE* s2;
329 BYTE* d1;
331 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
333 BYTE* stmp = s1 + spitch;
334 BYTE* dtmp = d1 + dpitch;
336 for(BYTE* s3 = s1 + (w-1)*2; s1 < s3; s1 += 2, d1 += 4)
338 *((WORD*)d1) = *((WORD*)s1);
339 *((WORD*)d1+1) =
340 ((((*((WORD*)s1)&0xf800) + (*((WORD*)s1+1)&0xf800)) >> 1)&0xf800)|
341 ((((*((WORD*)s1)&0x07e0) + (*((WORD*)s1+1)&0x07e0)) >> 1)&0x07e0)|
342 ((((*((WORD*)s1)&0x001f) + (*((WORD*)s1+1)&0x001f)) >> 1)&0x001f);
345 *((WORD*)d1) = *((WORD*)s1);
346 *((WORD*)d1+1) = *((WORD*)s1);
348 s1 += 2;
349 d1 += 4;
351 s1 = stmp;
352 d1 = dtmp;
355 AvgLines565(d, h*2, dpitch);
357 else if(subtype == MEDIASUBTYPE_RGB24)
359 BYTE* s1;
360 BYTE* s2;
361 BYTE* d1;
363 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch) // TODO: replace this mess with mmx code
365 BYTE* stmp = s1 + spitch;
366 BYTE* dtmp = d1 + dpitch;
368 for(BYTE* s3 = s1 + (w-1)*3; s1 < s3; s1 += 3, d1 += 6)
370 d1[0] = s1[0];
371 d1[1] = s1[1];
372 d1[2] = s1[2];
373 d1[3] = (s1[0]+s1[3])>>1;
374 d1[4] = (s1[1]+s1[4])>>1;
375 d1[5] = (s1[2]+s1[5])>>1;
378 d1[0] = d1[3] = s1[0];
379 d1[1] = d1[4] = s1[1];
380 d1[2] = d1[5] = s1[2];
382 s1 += 3;
383 d1 += 6;
385 s1 = stmp;
386 d1 = dtmp;
389 AvgLines8(d, h*2, dpitch);
391 else if(subtype == MEDIASUBTYPE_RGB32 || subtype == MEDIASUBTYPE_ARGB32)
393 BYTE* s1;
394 BYTE* s2;
395 BYTE* d1;
397 for(s1 = s, s2 = s + h*spitch, d1 = d; s1 < s2; d1 += dpitch)
399 BYTE* stmp = s1 + spitch;
400 BYTE* dtmp = d1 + dpitch;
402 __asm
404 mov esi, s1
405 mov edi, d1
407 mov ecx, w
408 dec ecx
410 pxor mm0, mm0
411 row_loop3:
412 movq mm1, [esi]
413 movq mm2, mm1
415 punpcklbw mm1, mm0 // mm1 = 00xx00r100g100b1
416 punpckhbw mm2, mm0 // mm2 = 00xx00r200g200b2
418 paddw mm2, mm1
419 psrlw mm2, 1 // mm2 = (mm1 + mm2) / 2
421 packuswb mm1, mm2
423 movq [edi], mm1
425 lea esi, [esi+4]
426 lea edi, [edi+8]
428 dec ecx
429 jnz row_loop3
431 mov s1, esi
432 mov d1, edi
435 *((DWORD*)d1) = *((DWORD*)s1);
436 *((DWORD*)d1+1) = *((DWORD*)s1);
438 s1 += 4;
439 d1 += 8;
441 s1 = stmp;
442 d1 = dtmp;
445 AvgLines8(d, h*2, dpitch);
448 __asm emms;
451 HRESULT Copy(BYTE* pSub, BYTE* pIn, CSize sub, CSize in, int bpp, const GUID& subtype, DWORD black)
453 int wIn = in.cx, hIn = in.cy, pitchIn = wIn*bpp>>3;
454 int wSub = sub.cx, hSub = sub.cy, pitchSub = wSub*bpp>>3;
455 bool fScale2x = wIn*2 <= wSub;
457 if(fScale2x) wIn <<= 1, hIn <<= 1;
459 int left = ((wSub - wIn)>>1)&~1;
460 int mid = wIn;
461 int right = left + ((wSub - wIn)&1);
463 int dpLeft = left*bpp>>3;
464 int dpMid = mid*bpp>>3;
465 int dpRight = right*bpp>>3;
467 ASSERT(wSub >= wIn);
470 int i = 0, j = 0;
472 j += (hSub - hIn) >> 1;
474 for(; i < j; i++, pSub += pitchSub)
476 memsetd(pSub, black, dpLeft+dpMid+dpRight);
479 j += hIn;
481 if(hIn > hSub)
482 pIn += pitchIn * ((hIn - hSub) >> (fScale2x?2:1));
484 if(fScale2x)
486 Scale2x(subtype,
487 pSub + dpLeft, pitchSub, pIn, pitchIn,
488 in.cx, (min(j, hSub) - i) >> 1);
490 for(int k = min(j, hSub); i < k; i++, pIn += pitchIn, pSub += pitchSub)
492 memsetd(pSub, black, dpLeft);
493 memsetd(pSub + dpLeft+dpMid, black, dpRight);
496 else
498 for(int k = min(j, hSub); i < k; i++, pIn += pitchIn, pSub += pitchSub)
500 memsetd(pSub, black, dpLeft);
501 memcpy(pSub + dpLeft, pIn, dpMid);
502 memsetd(pSub + dpLeft+dpMid, black, dpRight);
506 j = hSub;
508 for(; i < j; i++, pSub += pitchSub)
510 memsetd(pSub, black, dpLeft+dpMid+dpRight);
514 return NOERROR;
517 HRESULT CDirectVobSubFilter::Copy(BYTE* pSub, BYTE* pIn, CSize sub, CSize in, int bpp, const GUID& subtype, DWORD black)
519 return ::Copy(pSub, pIn, sub, in, bpp, subtype, black);
522 void CDirectVobSubFilter::PrintMessages(BYTE* pOut)
524 if(!m_hdc || !m_hbm)
525 return;
527 const GUID& subtype = m_pOutput->CurrentMediaType().subtype;
529 BITMAPINFOHEADER bihOut;
530 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
532 CString msg, tmp;
534 if(m_fOSD)
536 tmp.Format(_T("in: %dx%d %s\nout: %dx%d %s\n"),
537 m_w, m_h,
538 Subtype2String(m_pInput->CurrentMediaType().subtype),
539 bihOut.biWidth, bihOut.biHeight,
540 Subtype2String(m_pOutput->CurrentMediaType().subtype));
541 msg += tmp;
543 tmp.Format(_T("real fps: %.3f, current fps: %.3f\nmedia time: %d, subtitle time: %d [ms]\nframe number: %d (calculated)\nrate: %.4f\n"),
544 m_fps, m_fMediaFPSEnabled?m_MediaFPS:fabs(m_fps),
545 (int)m_tPrev.Millisecs(), (int)(CalcCurrentTime()/10000),
546 (int)(m_tPrev.m_time * m_fps / 10000000),
547 m_pInput->CurrentRate());
548 msg += tmp;
550 CAutoLock cAutoLock(&m_csQueueLock);
552 if(m_simple_provider)
554 int nSubPics = -1;
555 REFERENCE_TIME rtNow = -1, rtStart = -1, rtStop = -1;
556 m_simple_provider->GetStats(nSubPics, rtNow, rtStart, rtStop);
557 tmp.Format(_T("queue stats: %I64d - %I64d [ms]\n"), rtStart/10000, rtStop/10000);
558 msg += tmp;
560 for(int i = 0; i < nSubPics; i++)
562 m_simple_provider->GetStats(i, rtStart, rtStop);
563 tmp.Format(_T("%d: %I64d - %I64d [ms]\n"), i, rtStart/10000, rtStop/10000);
564 msg += tmp;
566 LogSubPicStartStop(rtStart, rtStop, tmp);
569 //color space
570 tmp.Format( _T("Colorspace: %ls %ls (%ls)\n"),
571 ColorConvTable::GetDefaultRangeType()==ColorConvTable::RANGE_PC ? _T("PC"):_T("TV"),
572 ColorConvTable::GetDefaultYUVType()==ColorConvTable::BT601 ? _T("BT.601"):_T("BT.709"),
573 m_xy_int_opt[INT_COLOR_SPACE]==CDirectVobSub::YuvMatrix_AUTO ? _T("Auto") :
574 m_xy_int_opt[INT_COLOR_SPACE]==CDirectVobSub::GUESS ? _T("Guessed") : _T("Forced") );
575 msg += tmp;
577 SIZE layout_size, script_playres;
578 XyGetSize(SIZE_LAYOUT_WITH, &layout_size);
579 XyGetSize(SIZE_ASS_PLAY_RESOLUTION, &script_playres);
580 tmp.Format( _T("Layout with size %dx%d, script playres %dx%d\n"),
581 layout_size.cx, layout_size.cy, script_playres.cx, script_playres.cy );
582 msg += tmp;
584 //print cache info
585 CachesInfo *caches_info = NULL;
586 XyFlyWeightInfo *xy_fw_info = NULL;
587 int tmp_size;
588 XyGetBin(DirectVobSubXyOptions::BIN_CACHES_INFO, reinterpret_cast<LPVOID*>(&caches_info), &tmp_size);
589 XyGetBin(DirectVobSubXyOptions::BIN_XY_FLY_WEIGHT_INFO, reinterpret_cast<LPVOID*>(&xy_fw_info), &tmp_size);
590 ASSERT(caches_info);
591 ASSERT(xy_fw_info);
592 tmp.Format(
593 _T("Cache :stored_num/hit_count/query_count\n")\
594 _T(" Parser cache 1:%ld/%ld/%ld\n")\
595 _T(" Parser cache 2:%ld/%ld/%ld\n")\
596 _T("\n")\
597 _T(" LV 4:%ld/%ld/%ld\t\t")\
598 _T(" LV 3:%ld/%ld/%ld\n")\
599 _T(" LV 2:%ld/%ld/%ld\t\t")\
600 _T(" LV 1:%ld/%ld/%ld\n")\
601 _T(" LV 0:%ld/%ld/%ld\n")\
602 _T("\n")\
603 _T(" bitmap :%ld/%ld/%ld\t\t")\
604 _T(" scan line:%ld/%ld/%ld\n")\
605 _T(" relay key:%ld/%ld/%ld\t\t")\
606 _T(" clipper :%ld/%ld/%ld\n")\
607 _T("\n")\
608 _T(" FW string pool :%ld/%ld/%ld\t\t")\
609 _T(" FW bitmap key pool:%ld/%ld/%ld\n")\
611 caches_info->text_info_cache_cur_item_num, caches_info->text_info_cache_hit_count, caches_info->text_info_cache_query_count,
612 caches_info->word_info_cache_cur_item_num, caches_info->word_info_cache_hit_count, caches_info->word_info_cache_query_count,
613 caches_info->path_cache_cur_item_num, caches_info->path_cache_hit_count, caches_info->path_cache_query_count,
614 caches_info->scanline_cache2_cur_item_num, caches_info->scanline_cache2_hit_count, caches_info->scanline_cache2_query_count,
615 caches_info->non_blur_cache_cur_item_num, caches_info->non_blur_cache_hit_count, caches_info->non_blur_cache_query_count,
616 caches_info->overlay_cache_cur_item_num, caches_info->overlay_cache_hit_count, caches_info->overlay_cache_query_count,
617 caches_info->interpolate_cache_cur_item_num, caches_info->interpolate_cache_hit_count, caches_info->interpolate_cache_query_count,
618 caches_info->bitmap_cache_cur_item_num, caches_info->bitmap_cache_hit_count, caches_info->bitmap_cache_query_count,
619 caches_info->scanline_cache_cur_item_num, caches_info->scanline_cache_hit_count, caches_info->scanline_cache_query_count,
620 caches_info->overlay_key_cache_cur_item_num, caches_info->overlay_key_cache_hit_count, caches_info->overlay_key_cache_query_count,
621 caches_info->clipper_cache_cur_item_num, caches_info->clipper_cache_hit_count, caches_info->clipper_cache_query_count,
623 xy_fw_info->xy_fw_string_w.cur_item_num, xy_fw_info->xy_fw_string_w.hit_count, xy_fw_info->xy_fw_string_w.query_count,
624 xy_fw_info->xy_fw_grouped_draw_items_hash_key.cur_item_num, xy_fw_info->xy_fw_grouped_draw_items_hash_key.hit_count, xy_fw_info->xy_fw_grouped_draw_items_hash_key.query_count
626 msg += tmp;
627 delete []caches_info;
630 if(msg.IsEmpty()) return;
632 HANDLE hOldBitmap = SelectObject(m_hdc, m_hbm);
633 HANDLE hOldFont = SelectObject(m_hdc, m_hfont);
635 SetTextColor(m_hdc, 0xffffff);
636 SetBkMode(m_hdc, TRANSPARENT);
637 SetMapMode(m_hdc, MM_TEXT);
639 BITMAP bm;
640 GetObject(m_hbm, sizeof(BITMAP), &bm);
642 CRect r(0, 0, bm.bmWidth, bm.bmHeight);
643 DrawText(m_hdc, msg, _tcslen(msg), &r, DT_CALCRECT|DT_EXTERNALLEADING|DT_NOPREFIX|DT_WORDBREAK);
645 r += CPoint(10, 10);
646 r &= CRect(0, 0, bm.bmWidth, bm.bmHeight);
648 DrawText(m_hdc, msg, _tcslen(msg), &r, DT_LEFT|DT_TOP|DT_NOPREFIX|DT_WORDBREAK);
650 BYTE* pIn = (BYTE*)bm.bmBits;
651 int pitchIn = bm.bmWidthBytes;
652 int pitchOut = bihOut.biWidth * bihOut.biBitCount >> 3;
654 if( subtype == MEDIASUBTYPE_YV12 || subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV
655 || subtype== MEDIASUBTYPE_NV12 || subtype==MEDIASUBTYPE_NV21 )
656 pitchOut = bihOut.biWidth;
657 else if (subtype == MEDIASUBTYPE_P010 || subtype == MEDIASUBTYPE_P016)
658 pitchOut = bihOut.biWidth * 2;
660 pitchIn = (pitchIn+3)&~3;
661 pitchOut = (pitchOut+3)&~3;
663 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)
665 pOut += pitchOut * (abs(bihOut.biHeight)-1);
666 pitchOut = -pitchOut;
669 pIn += pitchIn * r.top;
670 pOut += pitchOut * r.top;
672 for(int w = min(r.right, m_w), h = r.Height(); h--; pIn += pitchIn, pOut += pitchOut)
674 BltLineRGB32((DWORD*)pOut, pIn, w, subtype);
675 memsetd(pIn, 0xff000000, r.right*4);
678 SelectObject(m_hdc, hOldBitmap);
679 SelectObject(m_hdc, hOldFont);