FreeRDP
Loading...
Searching...
No Matches
encoding.c
1
20#include <winpr/assert.h>
21#include <winpr/winpr.h>
22
23#include "camera.h"
24
25#define TAG CHANNELS_TAG("rdpecam-video.client")
26
32UINT32 h264_get_max_bitrate(UINT32 height)
33{
34 static struct Bitrates
35 {
36 UINT32 height;
37 UINT32 bitrate; /* kbps */
38
39 } bitrates[] = {
40 /* source: https://livekit.io/webrtc/bitrate-guide (webcam streaming)
41 *
42 * sorted by height in descending order
43 */
44 { 1080, 2700 }, { 720, 1250 }, { 480, 700 }, { 360, 400 },
45 { 240, 170 }, { 180, 140 }, { 0, 100 },
46 };
47 const size_t nBitrates = ARRAYSIZE(bitrates);
48
49 for (size_t i = 0; i < nBitrates; i++)
50 {
51 if (height >= bitrates[i].height)
52 {
53 UINT32 bitrate = bitrates[i].bitrate;
54 WLog_DBG(TAG, "Setting h264 max bitrate: %u kbps", bitrate);
55 return bitrate * 1000;
56 }
57 }
58
59 WINPR_ASSERT(FALSE);
60 return 0;
61}
62
68FREERDP_VIDEO_FORMAT ecamToVideoFormat(CAM_MEDIA_FORMAT ecamFormat)
69{
70 switch (ecamFormat)
71 {
72 case CAM_MEDIA_FORMAT_YUY2:
73 return FREERDP_VIDEO_FORMAT_YUYV422;
74 case CAM_MEDIA_FORMAT_NV12:
75 return FREERDP_VIDEO_FORMAT_NV12;
76 case CAM_MEDIA_FORMAT_I420:
77 return FREERDP_VIDEO_FORMAT_YUV420P;
78 case CAM_MEDIA_FORMAT_RGB24:
79 return FREERDP_VIDEO_FORMAT_RGB24;
80 case CAM_MEDIA_FORMAT_RGB32:
81 return FREERDP_VIDEO_FORMAT_RGB32;
82 case CAM_MEDIA_FORMAT_H264:
83 return FREERDP_VIDEO_FORMAT_H264;
84 case CAM_MEDIA_FORMAT_MJPG:
85 return FREERDP_VIDEO_FORMAT_MJPEG;
86 default:
87 WLog_ERR(TAG, "Unsupported ecamFormat %u", ecamFormat);
88 return FREERDP_VIDEO_FORMAT_NONE;
89 }
90}
91
98static BOOL ecam_init_video_context(CameraDeviceStream* stream)
99{
100 WINPR_ASSERT(stream);
101
102 if (stream->video)
103 return TRUE;
104
105 stream->video =
106 freerdp_video_context_new(stream->currMediaType.Width, stream->currMediaType.Height);
107 if (!stream->video)
108 {
109 WLog_ERR(TAG, "freerdp_video_context_new failed");
110 return FALSE;
111 }
112
113 return TRUE;
114}
115
121BOOL ecam_encoder_context_init(CameraDeviceStream* stream)
122{
123 if (!ecam_init_video_context(stream))
124 return FALSE;
125
126 /* When capture and negotiated output formats match, the video converter copies
127 * samples unchanged. Skip the unused H.264 encoder setup so passthrough works
128 * without an encoder. */
129 if ((ecamToVideoFormat(streamInputFormat(stream)) != FREERDP_VIDEO_FORMAT_NONE) &&
130 (streamInputFormat(stream) == streamOutputFormat(stream)))
131 return TRUE;
132
133 const UINT32 framerate =
134 stream->currMediaType.FrameRateNumerator / stream->currMediaType.FrameRateDenominator;
135
136 if (!freerdp_video_context_reconfigure(stream->video, stream->currMediaType.Width,
137 stream->currMediaType.Height, framerate, 0,
138 H264_CAMERA_VIDEO_REAL_TIME))
139 {
140 WLog_ERR(TAG, "Failed to configure H.264 encoder");
141 return FALSE;
142 }
143
144 return TRUE;
145}
146
152BOOL ecam_encoder_context_free(CameraDeviceStream* stream)
153{
154 if (!stream)
155 return FALSE;
156
157 if (stream->video)
158 {
159 freerdp_video_context_free(stream->video);
160 stream->video = nullptr;
161 }
162
163 return TRUE;
164}
165
171BOOL ecam_encoder_compress(CameraDeviceStream* stream, const BYTE* srcData, size_t srcSize,
172 wStream* output)
173{
174 const FREERDP_VIDEO_FORMAT inputFormat = ecamToVideoFormat(streamInputFormat(stream));
175 const FREERDP_VIDEO_FORMAT outputFormat = ecamToVideoFormat(streamOutputFormat(stream));
176
177 if (!ecam_encoder_context_init(stream))
178 return FALSE;
179
180 return freerdp_video_sample_convert(stream->video, inputFormat, srcData, srcSize, outputFormat,
181 output);
182}