20 #include <winpr/assert.h>
21 #include <winpr/winpr.h>
25 #define TAG CHANNELS_TAG("rdpecam-video.client")
34 static struct Bitrates
44 { 1080, 2700 }, { 720, 1250 }, { 480, 700 }, { 360, 400 },
45 { 240, 170 }, { 180, 140 }, { 0, 100 },
47 const size_t nBitrates = ARRAYSIZE(bitrates);
49 UINT32 height = stream->currMediaType.Height;
51 for (
size_t i = 0; i < nBitrates; i++)
53 if (height >= bitrates[i].height)
55 UINT32 bitrate = bitrates[i].bitrate;
56 WLog_DBG(TAG,
"Setting h264 max bitrate: %u kbps", bitrate);
57 return bitrate * 1000;
70 static enum AVPixelFormat ecamToAVPixFormat(CAM_MEDIA_FORMAT ecamFormat)
74 case CAM_MEDIA_FORMAT_YUY2:
75 return AV_PIX_FMT_YUYV422;
76 case CAM_MEDIA_FORMAT_NV12:
77 return AV_PIX_FMT_NV12;
78 case CAM_MEDIA_FORMAT_I420:
79 return AV_PIX_FMT_YUV420P;
80 case CAM_MEDIA_FORMAT_RGB24:
81 return AV_PIX_FMT_RGB24;
82 case CAM_MEDIA_FORMAT_RGB32:
83 return AV_PIX_FMT_RGB32;
85 WLog_ERR(TAG,
"Unsupported ecamFormat %d", ecamFormat);
86 return AV_PIX_FMT_NONE;
96 static BOOL ecam_init_sws_context(
CameraDeviceStream* stream,
enum AVPixelFormat pixFormat)
106 case AV_PIX_FMT_YUVJ411P:
107 pixFormat = AV_PIX_FMT_YUV411P;
110 case AV_PIX_FMT_YUVJ420P:
111 pixFormat = AV_PIX_FMT_YUV420P;
114 case AV_PIX_FMT_YUVJ422P:
115 pixFormat = AV_PIX_FMT_YUV422P;
118 case AV_PIX_FMT_YUVJ440P:
119 pixFormat = AV_PIX_FMT_YUV440P;
122 case AV_PIX_FMT_YUVJ444P:
123 pixFormat = AV_PIX_FMT_YUV444P;
130 const int width = (int)stream->currMediaType.Width;
131 const int height = (
int)stream->currMediaType.Height;
133 stream->sws = sws_getContext(width, height, pixFormat, width, height, AV_PIX_FMT_YUV420P, 0,
137 WLog_ERR(TAG,
"sws_getContext failed");
149 static BOOL ecam_encoder_compress_h264(
CameraDeviceStream* stream,
const BYTE* srcData,
150 size_t srcSize, BYTE** ppDstData,
size_t* pDstSize)
153 BYTE* srcSlice[4] = { 0 };
154 int srcLineSizes[4] = { 0 };
155 BYTE* yuv420pData[3] = { 0 };
156 UINT32 yuv420pStride[3] = { 0 };
157 prim_size_t size = { stream->currMediaType.Width, stream->currMediaType.Height };
158 CAM_MEDIA_FORMAT inputFormat = streamInputFormat(stream);
159 enum AVPixelFormat pixFormat = AV_PIX_FMT_NONE;
161 #if defined(WITH_INPUT_FORMAT_MJPG)
162 if (inputFormat == CAM_MEDIA_FORMAT_MJPG)
164 stream->avInputPkt->data = WINPR_CAST_CONST_PTR_AWAY(srcData, uint8_t*);
165 WINPR_ASSERT(srcSize <= INT32_MAX);
166 stream->avInputPkt->size = (int)srcSize;
168 if (avcodec_send_packet(stream->avContext, stream->avInputPkt) < 0)
170 WLog_ERR(TAG,
"avcodec_send_packet failed");
174 if (avcodec_receive_frame(stream->avContext, stream->avOutFrame) < 0)
176 WLog_ERR(TAG,
"avcodec_receive_frame failed");
180 for (
size_t i = 0; i < 4; i++)
182 srcSlice[i] = stream->avOutFrame->data[i];
183 srcLineSizes[i] = stream->avOutFrame->linesize[i];
187 pixFormat = stream->avContext->pix_fmt;
192 pixFormat = ecamToAVPixFormat(inputFormat);
194 if (av_image_fill_linesizes(srcLineSizes, pixFormat, (
int)size.width) < 0)
196 WLog_ERR(TAG,
"av_image_fill_linesizes failed");
200 if (av_image_fill_pointers(srcSlice, pixFormat, (
int)size.height,
201 WINPR_CAST_CONST_PTR_AWAY(srcData, BYTE*), srcLineSizes) < 0)
203 WLog_ERR(TAG,
"av_image_fill_pointers failed");
209 if (h264_get_yuv_buffer(stream->h264, srcLineSizes[0], size.width, size.height, yuv420pData,
214 if (!ecam_init_sws_context(stream, pixFormat))
217 const BYTE* cSrcSlice[4] = { srcSlice[0], srcSlice[1], srcSlice[2], srcSlice[3] };
218 if (sws_scale(stream->sws, cSrcSlice, srcLineSizes, 0, (
int)size.height, yuv420pData,
219 (
int*)yuv420pStride) <= 0)
223 if (h264_compress(stream->h264, ppDstData, &dstSize) < 0)
237 WINPR_ASSERT(stream);
241 sws_freeContext(stream->sws);
245 #if defined(WITH_INPUT_FORMAT_MJPG)
246 if (stream->avOutFrame)
247 av_frame_free(&stream->avOutFrame);
249 if (stream->avInputPkt)
251 stream->avInputPkt->data = NULL;
252 stream->avInputPkt->size = 0;
253 av_packet_free(&stream->avInputPkt);
256 if (stream->avContext)
257 avcodec_free_context(&stream->avContext);
262 h264_context_free(stream->h264);
267 #if defined(WITH_INPUT_FORMAT_MJPG)
275 WINPR_ASSERT(stream);
277 const AVCodec* avcodec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
280 WLog_ERR(TAG,
"avcodec_find_decoder failed to find MJPEG codec");
284 stream->avContext = avcodec_alloc_context3(avcodec);
285 if (!stream->avContext)
287 WLog_ERR(TAG,
"avcodec_alloc_context3 failed");
291 stream->avContext->width = stream->currMediaType.Width;
292 stream->avContext->height = stream->currMediaType.Height;
296 stream->avContext->err_recognition |= AV_EF_EXPLODE;
298 if (avcodec_open2(stream->avContext, avcodec, NULL) < 0)
300 WLog_ERR(TAG,
"avcodec_open2 failed");
304 stream->avInputPkt = av_packet_alloc();
305 if (!stream->avInputPkt)
307 WLog_ERR(TAG,
"av_packet_alloc failed");
311 stream->avOutFrame = av_frame_alloc();
312 if (!stream->avOutFrame)
314 WLog_ERR(TAG,
"av_frame_alloc failed");
329 WINPR_ASSERT(stream);
332 stream->h264 = h264_context_new(TRUE);
336 WLog_ERR(TAG,
"h264_context_new failed");
340 if (!h264_context_reset(stream->h264, stream->currMediaType.Width,
341 stream->currMediaType.Height))
344 if (!h264_context_set_option(stream->h264, H264_CONTEXT_OPTION_USAGETYPE,
345 H264_CAMERA_VIDEO_REAL_TIME))
348 if (!h264_context_set_option(stream->h264, H264_CONTEXT_OPTION_FRAMERATE,
349 stream->currMediaType.FrameRateNumerator /
350 stream->currMediaType.FrameRateDenominator))
353 if (!h264_context_set_option(stream->h264, H264_CONTEXT_OPTION_BITRATE,
354 ecam_encoder_h264_get_max_bitrate(stream)))
357 if (!h264_context_set_option(stream->h264, H264_CONTEXT_OPTION_RATECONTROL,
358 H264_RATECONTROL_VBR))
361 if (!h264_context_set_option(stream->h264, H264_CONTEXT_OPTION_QP, 0))
364 #if defined(WITH_INPUT_FORMAT_MJPG)
365 if (streamInputFormat(stream) == CAM_MEDIA_FORMAT_MJPG && !ecam_init_mjpeg_decoder(stream))
372 ecam_encoder_context_free_h264(stream);
383 CAM_MEDIA_FORMAT format = streamOutputFormat(stream);
387 case CAM_MEDIA_FORMAT_H264:
388 return ecam_encoder_context_init_h264(stream);
391 WLog_ERR(TAG,
"Unsupported output format %d", format);
403 CAM_MEDIA_FORMAT format = streamOutputFormat(stream);
406 case CAM_MEDIA_FORMAT_H264:
407 ecam_encoder_context_free_h264(stream);
421 BOOL ecam_encoder_compress(
CameraDeviceStream* stream,
const BYTE* srcData,
size_t srcSize,
422 BYTE** ppDstData,
size_t* pDstSize)
424 CAM_MEDIA_FORMAT format = streamOutputFormat(stream);
427 case CAM_MEDIA_FORMAT_H264:
428 return ecam_encoder_compress_h264(stream, srcData, srcSize, ppDstData, pDstSize);
430 WLog_ERR(TAG,
"Unsupported output format %d", format);