FreeRDP
Loading...
Searching...
No Matches
nv12.c
1
18#include "nv12.h"
19#include "capture_policy.h"
20#include <winpr/assert.h>
21#include <VideoToolbox/VideoToolbox.h>
22
23OSStatus cam_avfoundation_pixel_transfer_create(CFTypeRef* transfer)
24{
25 WINPR_ASSERT(transfer);
26 *transfer = NULL;
27 VTPixelTransferSessionRef session = NULL;
28 OSStatus status = VTPixelTransferSessionCreate(NULL, &session);
29 if (status != noErr)
30 return status;
31 const int one = 1;
32 CFNumberRef spacing = CFNumberCreate(NULL, kCFNumberIntType, &one);
33 CFDictionaryRef aspect = NULL;
34 if (spacing)
35 {
36 const void* keys[] = { kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
37 kCVImageBufferPixelAspectRatioVerticalSpacingKey };
38 const void* values[] = { spacing, spacing };
39 aspect = CFDictionaryCreate(NULL, keys, values, 2, &kCFTypeDictionaryKeyCallBacks,
40 &kCFTypeDictionaryValueCallBacks);
41 CFRelease(spacing);
42 }
43 if (!aspect)
44 status = kVTAllocationFailedErr;
45 else
46 {
47 /* RDPECAM advertises square pixels and transmits no CoreVideo attachments.
48 * Fit the complete camera view without relying on pixel aspect metadata. */
49 status = VTSessionSetProperty(session, kVTPixelTransferPropertyKey_ScalingMode,
50 kVTScalingMode_Letterbox);
51 if (status == noErr)
52 status = VTSessionSetProperty(
53 session, kVTPixelTransferPropertyKey_DestinationPixelAspectRatio, aspect);
54 CFRelease(aspect);
55 }
56 if (status != noErr)
57 {
58 CFRelease(session);
59 return status;
60 }
61 *transfer = session;
62 return status;
63}
64
65BOOL cam_avfoundation_pixel_buffer_to_nv12(CVPixelBufferRef image, wStream* output)
66{
67 WINPR_ASSERT(image);
68 WINPR_ASSERT(output);
69 if ((CVPixelBufferGetPixelFormatType(image) !=
70 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) ||
71 (CVPixelBufferGetPlaneCount(image) != 2))
72 return FALSE;
73 const size_t width = CVPixelBufferGetWidth(image);
74 const size_t height = CVPixelBufferGetHeight(image);
75 if (!width || !height || (width % 2) || (height % 2) || (width > CAM_AVFOUNDATION_MAX_WIDTH) ||
76 (height > CAM_AVFOUNDATION_MAX_HEIGHT))
77 return FALSE;
78 if ((CVPixelBufferGetHeightOfPlane(image, 0) != height) ||
79 (CVPixelBufferGetHeightOfPlane(image, 1) != height / 2) ||
80 (CVPixelBufferGetBytesPerRowOfPlane(image, 0) < width) ||
81 (CVPixelBufferGetBytesPerRowOfPlane(image, 1) < width))
82 return FALSE;
83 Stream_ResetPosition(output);
84 if (!Stream_EnsureRemainingCapacity(output, width * height * 3 / 2) ||
85 (CVPixelBufferLockBaseAddress(image, kCVPixelBufferLock_ReadOnly) != kCVReturnSuccess))
86 return FALSE;
87 for (size_t plane = 0; plane < 2; plane++)
88 {
89 const BYTE* data = CVPixelBufferGetBaseAddressOfPlane(image, plane);
90 const size_t stride = CVPixelBufferGetBytesPerRowOfPlane(image, plane);
91 if (!data)
92 {
93 CVPixelBufferUnlockBaseAddress(image, kCVPixelBufferLock_ReadOnly);
94 return FALSE;
95 }
96 for (size_t row = 0; row < CVPixelBufferGetHeightOfPlane(image, plane); row++)
97 Stream_Write(output, data + row * stride, width);
98 }
99 CVPixelBufferUnlockBaseAddress(image, kCVPixelBufferLock_ReadOnly);
100 Stream_SealLength(output);
101 return TRUE;
102}