1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2016, Oblong Industries, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /* TODO:
33 * - Add support for interlaced content
34 * - Add support for MVC AVC
35 * - Wrap more configuration options and maybe move properties to derived
36 */
37
38 #ifdef HAVE_CONFIG_H
39 # include <config.h>
40 #endif
41 #ifdef _WIN32
42 # include <malloc.h>
43 #endif
44
45 #include <stdlib.h>
46
47 #include "gstmsdkenc.h"
48 #include "gstmsdkbufferpool.h"
49 #include "gstmsdkvideomemory.h"
50 #include "gstmsdksystemmemory.h"
51 #include "gstmsdkcontextutil.h"
52
53 #ifndef _WIN32
54 #include "gstmsdkallocator_libva.h"
55 #endif
56
57 static inline void *
_aligned_alloc(size_t alignment,size_t size)58 _aligned_alloc (size_t alignment, size_t size)
59 {
60 #ifdef _WIN32
61 return _aligned_malloc (size, alignment);
62 #else
63 void *out;
64 if (posix_memalign (&out, alignment, size) != 0)
65 out = NULL;
66 return out;
67 #endif
68 }
69
70 #ifndef _WIN32
71 #define _aligned_free free
72 #endif
73
74 static void gst_msdkenc_close_encoder (GstMsdkEnc * thiz);
75
76 GST_DEBUG_CATEGORY_EXTERN (gst_msdkenc_debug);
77 #define GST_CAT_DEFAULT gst_msdkenc_debug
78
79 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
80 GST_PAD_SINK,
81 GST_PAD_ALWAYS,
82 GST_STATIC_CAPS ("video/x-raw, "
83 "format = (string) { NV12, I420, YV12, YUY2, UYVY, BGRA }, "
84 "framerate = (fraction) [0, MAX], "
85 "width = (int) [ 16, MAX ], height = (int) [ 16, MAX ],"
86 "interlace-mode = (string) progressive" ";"
87 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_DMABUF,
88 "{ NV12 }")));
89
90 #define PROP_HARDWARE_DEFAULT TRUE
91 #define PROP_ASYNC_DEPTH_DEFAULT 4
92 #define PROP_TARGET_USAGE_DEFAULT (MFX_TARGETUSAGE_BALANCED)
93 #define PROP_RATE_CONTROL_DEFAULT (MFX_RATECONTROL_CBR)
94 #define PROP_BITRATE_DEFAULT (2 * 1024)
95 #define PROP_QPI_DEFAULT 0
96 #define PROP_QPP_DEFAULT 0
97 #define PROP_QPB_DEFAULT 0
98 #define PROP_GOP_SIZE_DEFAULT 256
99 #define PROP_REF_FRAMES_DEFAULT 1
100 #define PROP_I_FRAMES_DEFAULT 0
101 #define PROP_B_FRAMES_DEFAULT 0
102 #define PROP_NUM_SLICES_DEFAULT 0
103 #define PROP_AVBR_ACCURACY_DEFAULT 0
104 #define PROP_AVBR_CONVERGENCE_DEFAULT 0
105 #define PROP_RC_LOOKAHEAD_DEPTH_DEFAULT 10
106 #define PROP_MAX_VBV_BITRATE_DEFAULT 0
107 #define PROP_MAX_FRAME_SIZE_DEFAULT 0
108 #define PROP_MBBRC_DEFAULT MFX_CODINGOPTION_OFF
109 #define PROP_ADAPTIVE_I_DEFAULT MFX_CODINGOPTION_OFF
110 #define PROP_ADAPTIVE_B_DEFAULT MFX_CODINGOPTION_OFF
111
112 #define gst_msdkenc_parent_class parent_class
113 G_DEFINE_TYPE (GstMsdkEnc, gst_msdkenc, GST_TYPE_VIDEO_ENCODER);
114
115 typedef struct
116 {
117 mfxFrameSurface1 *surface;
118 GstBuffer *buf;
119 } MsdkSurface;
120
121 void
gst_msdkenc_add_extra_param(GstMsdkEnc * thiz,mfxExtBuffer * param)122 gst_msdkenc_add_extra_param (GstMsdkEnc * thiz, mfxExtBuffer * param)
123 {
124 if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
125 thiz->extra_params[thiz->num_extra_params] = param;
126 thiz->num_extra_params++;
127 }
128 }
129
130 static void
gst_msdkenc_set_context(GstElement * element,GstContext * context)131 gst_msdkenc_set_context (GstElement * element, GstContext * context)
132 {
133 GstMsdkContext *msdk_context = NULL;
134 GstMsdkEnc *thiz = GST_MSDKENC (element);
135
136 if (gst_msdk_context_get_context (context, &msdk_context)) {
137 gst_object_replace ((GstObject **) & thiz->context,
138 (GstObject *) msdk_context);
139 gst_object_unref (msdk_context);
140 }
141
142 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
143 }
144
145 static void
ensure_bitrate_control(GstMsdkEnc * thiz)146 ensure_bitrate_control (GstMsdkEnc * thiz)
147 {
148 mfxInfoMFX *mfx = &thiz->param.mfx;
149 mfxExtCodingOption2 *option2 = &thiz->option2;
150 mfxExtCodingOption3 *option3 = &thiz->option3;
151
152 mfx->RateControlMethod = thiz->rate_control;
153 /* No effect in CQP varient algorithms */
154 if ((mfx->RateControlMethod != MFX_RATECONTROL_CQP) &&
155 (thiz->bitrate > G_MAXUINT16 || thiz->max_vbv_bitrate > G_MAXUINT16)) {
156 mfxU32 max_val = MAX (thiz->max_vbv_bitrate, thiz->bitrate);
157
158 mfx->BRCParamMultiplier = (mfxU16) ((max_val + 0x10000) / 0x10000);
159 mfx->TargetKbps = (mfxU16) (thiz->bitrate / mfx->BRCParamMultiplier);
160 mfx->MaxKbps = (mfxU16) (thiz->max_vbv_bitrate / mfx->BRCParamMultiplier);
161 mfx->BufferSizeInKB =
162 (mfxU16) (mfx->BufferSizeInKB / mfx->BRCParamMultiplier);
163 /* Currently InitialDelayInKB is not used in this plugin */
164 mfx->InitialDelayInKB =
165 (mfxU16) (mfx->InitialDelayInKB / mfx->BRCParamMultiplier);
166 } else {
167 mfx->TargetKbps = thiz->bitrate;
168 mfx->MaxKbps = thiz->max_vbv_bitrate;
169 mfx->BRCParamMultiplier = 1;
170 }
171
172 switch (mfx->RateControlMethod) {
173 case MFX_RATECONTROL_CQP:
174 mfx->QPI = thiz->qpi;
175 mfx->QPP = thiz->qpp;
176 mfx->QPB = thiz->qpb;
177 break;
178
179 case MFX_RATECONTROL_LA_ICQ:
180 option2->LookAheadDepth = thiz->lookahead_depth;
181 case MFX_RATECONTROL_ICQ:
182 mfx->ICQQuality = CLAMP (thiz->qpi, 1, 51);
183 break;
184
185 case MFX_RATECONTROL_LA: /* VBR with LA. Only supported in H264?? */
186 case MFX_RATECONTROL_LA_HRD: /* VBR with LA, HRD compliant */
187 option2->LookAheadDepth = thiz->lookahead_depth;
188 break;
189
190 case MFX_RATECONTROL_QVBR:
191 option3->QVBRQuality = CLAMP (thiz->qpi, 1, 51);
192 thiz->enable_extopt3 = TRUE;
193 break;
194
195 case MFX_RATECONTROL_AVBR:
196 mfx->Accuracy = thiz->accuracy;
197 mfx->Convergence = thiz->convergence;
198 break;
199
200 case MFX_RATECONTROL_VBR:
201 option2->MaxFrameSize = thiz->max_frame_size * 1000;
202 break;
203
204 case MFX_RATECONTROL_VCM:
205 /*Non HRD compliant mode with no B-frame and interlaced support */
206 thiz->param.mfx.GopRefDist = 0;
207 break;
208
209 case MFX_RATECONTROL_CBR:
210 break;
211
212 default:
213 GST_ERROR ("Unsupported RateControl!");
214 break;
215 }
216 }
217
218 void
gst_msdkenc_ensure_extended_coding_options(GstMsdkEnc * thiz)219 gst_msdkenc_ensure_extended_coding_options (GstMsdkEnc * thiz)
220 {
221 mfxExtCodingOption2 *option2 = &thiz->option2;
222 mfxExtCodingOption3 *option3 = &thiz->option3;
223
224 /* Fill ExtendedCodingOption2, set non-zero defaults too */
225 option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
226 option2->Header.BufferSz = sizeof (thiz->option2);
227 option2->MBBRC = thiz->mbbrc;
228 option2->AdaptiveI = thiz->adaptive_i;
229 option2->AdaptiveB = thiz->adaptive_b;
230 option2->BitrateLimit = MFX_CODINGOPTION_OFF;
231 option2->EnableMAD = MFX_CODINGOPTION_OFF;
232 option2->UseRawRef = MFX_CODINGOPTION_OFF;
233 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option2);
234
235 if (thiz->enable_extopt3) {
236 option3->Header.BufferId = MFX_EXTBUFF_CODING_OPTION3;
237 option3->Header.BufferSz = sizeof (thiz->option3);
238 gst_msdkenc_add_extra_param (thiz, (mfxExtBuffer *) option3);
239 }
240 }
241
242 static gboolean
gst_msdkenc_init_encoder(GstMsdkEnc * thiz)243 gst_msdkenc_init_encoder (GstMsdkEnc * thiz)
244 {
245 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
246 GstVideoInfo *info;
247 mfxSession session;
248 mfxStatus status;
249 mfxFrameAllocRequest request[2];
250 guint i;
251
252 if (thiz->initialized)
253 return TRUE;
254
255 if (!thiz->context) {
256 GST_WARNING_OBJECT (thiz, "No MSDK Context");
257 return FALSE;
258 }
259
260 if (!thiz->input_state) {
261 GST_DEBUG_OBJECT (thiz, "Have no input state yet");
262 return FALSE;
263 }
264 info = &thiz->input_state->info;
265
266 GST_OBJECT_LOCK (thiz);
267 session = gst_msdk_context_get_session (thiz->context);
268
269 thiz->has_vpp = FALSE;
270 if (thiz->use_video_memory)
271 gst_msdk_set_frame_allocator (thiz->context);
272
273 /* Check 10bit input */
274 if (GST_VIDEO_INFO_COMP_DEPTH (info, 0) == 10) {
275 if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_P010_10LE) {
276 GST_WARNING_OBJECT (thiz,
277 "P010_10LE is the only supported 10bit format\n");
278 goto failed;
279 }
280 } else if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_NV12) {
281 if (thiz->use_video_memory)
282 thiz->vpp_param.IOPattern =
283 MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
284 else
285 thiz->vpp_param.IOPattern =
286 MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
287
288 thiz->vpp_param.vpp.In.Width = GST_ROUND_UP_16 (info->width);
289 thiz->vpp_param.vpp.In.Height = GST_ROUND_UP_32 (info->height);
290 thiz->vpp_param.vpp.In.CropW = info->width;
291 thiz->vpp_param.vpp.In.CropH = info->height;
292 thiz->vpp_param.vpp.In.FrameRateExtN = info->fps_n;
293 thiz->vpp_param.vpp.In.FrameRateExtD = info->fps_d;
294 thiz->vpp_param.vpp.In.AspectRatioW = info->par_n;
295 thiz->vpp_param.vpp.In.AspectRatioH = info->par_d;
296 thiz->vpp_param.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
297 switch (GST_VIDEO_INFO_FORMAT (info)) {
298 case GST_VIDEO_FORMAT_NV12:
299 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_NV12;
300 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
301 break;
302 case GST_VIDEO_FORMAT_YV12:
303 case GST_VIDEO_FORMAT_I420:
304 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YV12;
305 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
306 break;
307 case GST_VIDEO_FORMAT_YUY2:
308 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_YUY2;
309 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
310 break;
311 case GST_VIDEO_FORMAT_UYVY:
312 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_UYVY;
313 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
314 break;
315 case GST_VIDEO_FORMAT_BGRA:
316 thiz->vpp_param.vpp.In.FourCC = MFX_FOURCC_RGB4;
317 thiz->vpp_param.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
318 break;
319 default:
320 g_assert_not_reached ();
321 break;
322 }
323 thiz->vpp_param.vpp.Out = thiz->vpp_param.vpp.In;
324 thiz->vpp_param.vpp.Out.FourCC = MFX_FOURCC_NV12;
325 thiz->vpp_param.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
326
327 /* validate parameters and allow the Media SDK to make adjustments */
328 status = MFXVideoVPP_Query (session, &thiz->vpp_param, &thiz->vpp_param);
329 if (status < MFX_ERR_NONE) {
330 GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
331 msdk_status_to_string (status));
332 goto no_vpp;
333 } else if (status > MFX_ERR_NONE) {
334 GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
335 msdk_status_to_string (status));
336 }
337
338 status = MFXVideoVPP_QueryIOSurf (session, &thiz->vpp_param, request);
339 if (status < MFX_ERR_NONE) {
340 GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
341 msdk_status_to_string (status));
342 goto no_vpp;
343 } else if (status > MFX_ERR_NONE) {
344 GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
345 msdk_status_to_string (status));
346 }
347
348 if (thiz->use_video_memory)
349 request[0].NumFrameSuggested +=
350 gst_msdk_context_get_shared_async_depth (thiz->context);
351 thiz->num_vpp_surfaces = request[0].NumFrameSuggested;
352
353 if (thiz->use_video_memory)
354 gst_msdk_frame_alloc (thiz->context, &(request[0]),
355 &thiz->vpp_alloc_resp);
356
357 status = MFXVideoVPP_Init (session, &thiz->vpp_param);
358 if (status < MFX_ERR_NONE) {
359 GST_ERROR_OBJECT (thiz, "Init failed (%s)",
360 msdk_status_to_string (status));
361 goto no_vpp;
362 } else if (status > MFX_ERR_NONE) {
363 GST_WARNING_OBJECT (thiz, "Init returned: %s",
364 msdk_status_to_string (status));
365 }
366
367 status = MFXVideoVPP_GetVideoParam (session, &thiz->vpp_param);
368 if (status < MFX_ERR_NONE) {
369 mfxStatus status1;
370 GST_ERROR_OBJECT (thiz, "Get VPP Parameters failed (%s)",
371 msdk_status_to_string (status));
372 status1 = MFXVideoVPP_Close (session);
373 if (status1 != MFX_ERR_NONE && status1 != MFX_ERR_NOT_INITIALIZED)
374 GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
375 msdk_status_to_string (status1));
376
377 goto no_vpp;
378 } else if (status > MFX_ERR_NONE) {
379 GST_WARNING_OBJECT (thiz, "Get VPP Parameters returned: %s",
380 msdk_status_to_string (status));
381 }
382
383 thiz->has_vpp = TRUE;
384 }
385
386 thiz->param.AsyncDepth = thiz->async_depth;
387 if (thiz->use_video_memory)
388 thiz->param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
389 else
390 thiz->param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
391
392 thiz->param.mfx.TargetUsage = thiz->target_usage;
393 thiz->param.mfx.GopPicSize = thiz->gop_size;
394 thiz->param.mfx.GopRefDist = thiz->b_frames + 1;
395 thiz->param.mfx.IdrInterval = thiz->i_frames;
396 thiz->param.mfx.NumSlice = thiz->num_slices;
397 thiz->param.mfx.NumRefFrame = thiz->ref_frames;
398 thiz->param.mfx.EncodedOrder = 0; /* Take input frames in display order */
399
400 thiz->param.mfx.FrameInfo.Width = GST_ROUND_UP_16 (info->width);
401 thiz->param.mfx.FrameInfo.Height = GST_ROUND_UP_32 (info->height);
402 thiz->param.mfx.FrameInfo.CropW = info->width;
403 thiz->param.mfx.FrameInfo.CropH = info->height;
404 thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
405 thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
406 thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
407 thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
408 thiz->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
409 thiz->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
410
411 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_P010_10LE) {
412 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_P010;
413 thiz->param.mfx.FrameInfo.BitDepthLuma = 10;
414 thiz->param.mfx.FrameInfo.BitDepthChroma = 10;
415 thiz->param.mfx.FrameInfo.Shift = 1;
416 } else {
417 thiz->param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
418 thiz->param.mfx.FrameInfo.BitDepthLuma = 8;
419 thiz->param.mfx.FrameInfo.BitDepthChroma = 8;
420 }
421
422 /* ensure bitrate control parameters */
423 ensure_bitrate_control (thiz);
424
425 /* allow subclass configure further */
426 if (klass->configure) {
427 if (!klass->configure (thiz))
428 goto failed;
429 }
430
431 if (thiz->num_extra_params) {
432 thiz->param.NumExtParam = thiz->num_extra_params;
433 thiz->param.ExtParam = thiz->extra_params;
434 }
435
436 /* validate parameters and allow the Media SDK to make adjustments */
437 status = MFXVideoENCODE_Query (session, &thiz->param, &thiz->param);
438 if (status < MFX_ERR_NONE) {
439 GST_ERROR_OBJECT (thiz, "Video Encode Query failed (%s)",
440 msdk_status_to_string (status));
441 goto failed;
442 } else if (status > MFX_ERR_NONE) {
443 GST_WARNING_OBJECT (thiz, "Video Encode Query returned: %s",
444 msdk_status_to_string (status));
445 }
446
447 status = MFXVideoENCODE_QueryIOSurf (session, &thiz->param, request);
448 if (status < MFX_ERR_NONE) {
449 GST_ERROR_OBJECT (thiz, "Encode Query IO surfaces failed (%s)",
450 msdk_status_to_string (status));
451 goto failed;
452 } else if (status > MFX_ERR_NONE) {
453 GST_WARNING_OBJECT (thiz, "Encode Query IO surfaces returned: %s",
454 msdk_status_to_string (status));
455 }
456
457 if (thiz->has_vpp)
458 request[0].NumFrameSuggested += thiz->num_vpp_surfaces + 1 - 4;
459
460 if (thiz->use_video_memory) {
461 if (thiz->use_dmabuf && !thiz->has_vpp)
462 request[0].Type |= MFX_MEMTYPE_EXPORT_FRAME;
463 gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->alloc_resp);
464 }
465
466 /* Maximum of VPP output and encoder input, if using VPP */
467 if (thiz->has_vpp)
468 request[0].NumFrameSuggested =
469 MAX (request[0].NumFrameSuggested, request[1].NumFrameSuggested);
470 if (request[0].NumFrameSuggested < thiz->param.AsyncDepth) {
471 GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
472 request[0].NumFrameMin, request[0].NumFrameSuggested,
473 thiz->param.AsyncDepth);
474 goto failed;
475 }
476
477 /* This is VPP output (if any) and encoder input */
478 thiz->num_surfaces = request[0].NumFrameSuggested;
479
480 GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested), allocated %d",
481 request[0].NumFrameMin, request[0].NumFrameSuggested, thiz->num_surfaces);
482
483 status = MFXVideoENCODE_Init (session, &thiz->param);
484 if (status < MFX_ERR_NONE) {
485 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
486 goto failed;
487 } else if (status > MFX_ERR_NONE) {
488 GST_WARNING_OBJECT (thiz, "Init returned: %s",
489 msdk_status_to_string (status));
490 }
491
492 status = MFXVideoENCODE_GetVideoParam (session, &thiz->param);
493 if (status < MFX_ERR_NONE) {
494 GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
495 msdk_status_to_string (status));
496 goto failed;
497 } else if (status > MFX_ERR_NONE) {
498 GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
499 msdk_status_to_string (status));
500 }
501
502 thiz->num_tasks = thiz->param.AsyncDepth;
503 thiz->tasks = g_new0 (MsdkEncTask, thiz->num_tasks);
504 for (i = 0; i < thiz->num_tasks; i++) {
505 thiz->tasks[i].output_bitstream.Data = _aligned_alloc (32,
506 thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
507 1024);
508 if (!thiz->tasks[i].output_bitstream.Data) {
509 GST_ERROR_OBJECT (thiz, "Memory allocation failed");
510 goto failed;
511 }
512 thiz->tasks[i].output_bitstream.MaxLength =
513 thiz->param.mfx.BufferSizeInKB * thiz->param.mfx.BRCParamMultiplier *
514 1024;
515 }
516 thiz->next_task = 0;
517
518 thiz->reconfig = FALSE;
519 thiz->initialized = TRUE;
520
521 GST_OBJECT_UNLOCK (thiz);
522
523 return TRUE;
524
525 no_vpp:
526 failed:
527 GST_OBJECT_UNLOCK (thiz);
528 return FALSE;
529 }
530
531 static void
gst_msdkenc_close_encoder(GstMsdkEnc * thiz)532 gst_msdkenc_close_encoder (GstMsdkEnc * thiz)
533 {
534 guint i;
535 mfxStatus status;
536
537 if (!thiz->context || !thiz->initialized)
538 return;
539
540 GST_DEBUG_OBJECT (thiz, "Closing encoder with context %" GST_PTR_FORMAT,
541 thiz->context);
542
543 gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL);
544 gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL);
545
546 if (thiz->use_video_memory)
547 gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
548
549 status = MFXVideoENCODE_Close (gst_msdk_context_get_session (thiz->context));
550 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
551 GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
552 msdk_status_to_string (status));
553 }
554
555 if (thiz->tasks) {
556 for (i = 0; i < thiz->num_tasks; i++) {
557 MsdkEncTask *task = &thiz->tasks[i];
558 if (task->output_bitstream.Data) {
559 _aligned_free (task->output_bitstream.Data);
560 }
561 }
562 }
563 g_free (thiz->tasks);
564 thiz->tasks = NULL;
565
566 /* Close VPP before freeing the surfaces. They are shared between encoder
567 * and VPP */
568 if (thiz->has_vpp) {
569 if (thiz->use_video_memory)
570 gst_msdk_frame_free (thiz->context, &thiz->vpp_alloc_resp);
571
572 status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
573 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
574 GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
575 msdk_status_to_string (status));
576 }
577 }
578
579 memset (&thiz->param, 0, sizeof (thiz->param));
580 thiz->num_extra_params = 0;
581 thiz->initialized = FALSE;
582 }
583
584 typedef struct
585 {
586 GstVideoCodecFrame *frame;
587 MsdkSurface *frame_surface;
588 MsdkSurface *converted_surface;
589 } FrameData;
590
591 static FrameData *
gst_msdkenc_queue_frame(GstMsdkEnc * thiz,GstVideoCodecFrame * frame,GstVideoInfo * info)592 gst_msdkenc_queue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame,
593 GstVideoInfo * info)
594 {
595 FrameData *fdata;
596
597 fdata = g_slice_new (FrameData);
598 fdata->frame = gst_video_codec_frame_ref (frame);
599
600 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
601
602 return fdata;
603 }
604
605 static MsdkSurface *
gst_msdkenc_create_surface(mfxFrameSurface1 * surface,GstBuffer * buf)606 gst_msdkenc_create_surface (mfxFrameSurface1 * surface, GstBuffer * buf)
607 {
608 MsdkSurface *msdk_surface;
609 msdk_surface = g_slice_new0 (MsdkSurface);
610 msdk_surface->surface = surface;
611 msdk_surface->buf = buf;
612
613 return msdk_surface;
614 }
615
616 static void
gst_msdkenc_free_surface(MsdkSurface * surface)617 gst_msdkenc_free_surface (MsdkSurface * surface)
618 {
619 if (surface->buf)
620 gst_buffer_unref (surface->buf);
621
622 g_slice_free (MsdkSurface, surface);
623 }
624
625 static void
gst_msdkenc_free_frame_data(GstMsdkEnc * thiz,FrameData * fdata)626 gst_msdkenc_free_frame_data (GstMsdkEnc * thiz, FrameData * fdata)
627 {
628 if (fdata->frame_surface)
629 gst_msdkenc_free_surface (fdata->frame_surface);
630 if (thiz->has_vpp)
631 gst_msdkenc_free_surface (fdata->converted_surface);
632
633 gst_video_codec_frame_unref (fdata->frame);
634 g_slice_free (FrameData, fdata);
635 }
636
637 static void
gst_msdkenc_dequeue_frame(GstMsdkEnc * thiz,GstVideoCodecFrame * frame)638 gst_msdkenc_dequeue_frame (GstMsdkEnc * thiz, GstVideoCodecFrame * frame)
639 {
640 GList *l;
641
642 for (l = thiz->pending_frames; l; l = l->next) {
643 FrameData *fdata = l->data;
644
645 if (fdata->frame != frame)
646 continue;
647
648 gst_msdkenc_free_frame_data (thiz, fdata);
649
650 thiz->pending_frames = g_list_delete_link (thiz->pending_frames, l);
651 return;
652 }
653 }
654
655 static void
gst_msdkenc_dequeue_all_frames(GstMsdkEnc * thiz)656 gst_msdkenc_dequeue_all_frames (GstMsdkEnc * thiz)
657 {
658 GList *l;
659
660 for (l = thiz->pending_frames; l; l = l->next) {
661 FrameData *fdata = l->data;
662
663 gst_msdkenc_free_frame_data (thiz, fdata);
664 }
665 g_list_free (thiz->pending_frames);
666 thiz->pending_frames = NULL;
667 }
668
669 static MsdkEncTask *
gst_msdkenc_get_free_task(GstMsdkEnc * thiz)670 gst_msdkenc_get_free_task (GstMsdkEnc * thiz)
671 {
672 MsdkEncTask *tasks = thiz->tasks;
673 guint size = thiz->num_tasks;
674 guint start = thiz->next_task;
675 guint i;
676
677 if (tasks) {
678 for (i = 0; i < size; i++) {
679 guint t = (start + i) % size;
680 if (tasks[t].sync_point == NULL)
681 return &tasks[t];
682 }
683 }
684 return NULL;
685 }
686
687 static void
gst_msdkenc_reset_task(MsdkEncTask * task)688 gst_msdkenc_reset_task (MsdkEncTask * task)
689 {
690 task->output_bitstream.DataLength = 0;
691 task->sync_point = NULL;
692 }
693
694 static GstFlowReturn
gst_msdkenc_finish_frame(GstMsdkEnc * thiz,MsdkEncTask * task,gboolean discard)695 gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task,
696 gboolean discard)
697 {
698 GstVideoCodecFrame *frame;
699
700 if (!task->sync_point)
701 return GST_FLOW_OK;
702
703 frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
704
705 if (!frame) {
706 GST_ERROR_OBJECT (thiz, "failed to get a frame");
707 return GST_FLOW_ERROR;
708 }
709
710 /* Wait for encoding operation to complete, the magic number 300000 below
711 * is used in MSDK samples
712 * #define MSDK_ENC_WAIT_INTERVAL 300000
713 */
714 if (MFXVideoCORE_SyncOperation (gst_msdk_context_get_session (thiz->context),
715 task->sync_point, 300000) != MFX_ERR_NONE)
716 GST_WARNING_OBJECT (thiz, "failed to do sync operation");
717
718 if (!discard && task->output_bitstream.DataLength) {
719 GstBuffer *out_buf = NULL;
720 guint8 *data =
721 task->output_bitstream.Data + task->output_bitstream.DataOffset;
722 gsize size = task->output_bitstream.DataLength;
723 out_buf = gst_buffer_new_allocate (NULL, size, NULL);
724 gst_buffer_fill (out_buf, 0, data, size);
725 frame->output_buffer = out_buf;
726 frame->pts =
727 gst_util_uint64_scale (task->output_bitstream.TimeStamp, GST_SECOND,
728 90000);
729 frame->dts =
730 gst_util_uint64_scale (task->output_bitstream.DecodeTimeStamp,
731 GST_SECOND, 90000);
732
733 if ((task->output_bitstream.FrameType & MFX_FRAMETYPE_IDR) != 0 ||
734 (task->output_bitstream.FrameType & MFX_FRAMETYPE_xIDR) != 0) {
735 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
736 }
737
738 /* Mark task as available */
739 gst_msdkenc_reset_task (task);
740 }
741
742 gst_video_codec_frame_unref (frame);
743 gst_msdkenc_dequeue_frame (thiz, frame);
744
745 return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
746 }
747
748 static GstFlowReturn
gst_msdkenc_encode_frame(GstMsdkEnc * thiz,mfxFrameSurface1 * surface,GstVideoCodecFrame * input_frame)749 gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface,
750 GstVideoCodecFrame * input_frame)
751 {
752 mfxSession session;
753 MsdkEncTask *task;
754 mfxStatus status;
755
756 if (G_UNLIKELY (thiz->context == NULL)) {
757 gst_msdkenc_dequeue_frame (thiz, input_frame);
758 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
759 return GST_FLOW_NOT_NEGOTIATED;
760 }
761 session = gst_msdk_context_get_session (thiz->context);
762
763 task = gst_msdkenc_get_free_task (thiz);
764
765 for (;;) {
766 /* Force key-frame if needed */
767 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (input_frame))
768 thiz->enc_cntrl.FrameType =
769 MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF;
770 else
771 thiz->enc_cntrl.FrameType = MFX_FRAMETYPE_UNKNOWN;
772
773 status =
774 MFXVideoENCODE_EncodeFrameAsync (session, &thiz->enc_cntrl, surface,
775 &task->output_bitstream, &task->sync_point);
776 if (status != MFX_WRN_DEVICE_BUSY)
777 break;
778 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
779 g_usleep (1000);
780 };
781
782 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
783 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
784 ("MSDK encode error (%s)", msdk_status_to_string (status)));
785 gst_msdkenc_dequeue_frame (thiz, input_frame);
786 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), input_frame);
787 return GST_FLOW_ERROR;
788 }
789
790 if (task->sync_point) {
791 thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
792 } else if (status == MFX_ERR_MORE_DATA) {
793 gst_msdkenc_dequeue_frame (thiz, input_frame);
794 }
795
796 /* Ensure that next task is available */
797 task = thiz->tasks + thiz->next_task;
798 return gst_msdkenc_finish_frame (thiz, task, FALSE);
799 }
800
801 static guint
gst_msdkenc_maximum_delayed_frames(GstMsdkEnc * thiz)802 gst_msdkenc_maximum_delayed_frames (GstMsdkEnc * thiz)
803 {
804 return thiz->num_tasks;
805 }
806
807 static void
gst_msdkenc_set_latency(GstMsdkEnc * thiz)808 gst_msdkenc_set_latency (GstMsdkEnc * thiz)
809 {
810 GstVideoInfo *info = &thiz->input_state->info;
811 gint max_delayed_frames;
812 GstClockTime latency;
813
814 max_delayed_frames = gst_msdkenc_maximum_delayed_frames (thiz);
815
816 if (info->fps_n) {
817 latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
818 max_delayed_frames, info->fps_n);
819 } else {
820 /* FIXME: Assume 25fps. This is better than reporting no latency at
821 * all and then later failing in live pipelines
822 */
823 latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
824 max_delayed_frames, 25);
825 }
826
827 GST_INFO_OBJECT (thiz,
828 "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
829 GST_TIME_ARGS (latency), max_delayed_frames);
830
831 gst_video_encoder_set_latency (GST_VIDEO_ENCODER (thiz), latency, latency);
832 }
833
834 static void
gst_msdkenc_flush_frames(GstMsdkEnc * thiz,gboolean discard)835 gst_msdkenc_flush_frames (GstMsdkEnc * thiz, gboolean discard)
836 {
837 mfxStatus status;
838 mfxSession session;
839 MsdkEncTask *task;
840 guint i, t;
841
842 if (!thiz->tasks)
843 return;
844
845 session = gst_msdk_context_get_session (thiz->context);
846
847 for (;;) {
848 task = thiz->tasks + thiz->next_task;
849 gst_msdkenc_finish_frame (thiz, task, FALSE);
850
851 status = MFXVideoENCODE_EncodeFrameAsync (session, NULL, NULL,
852 &task->output_bitstream, &task->sync_point);
853
854 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
855 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."),
856 ("MSDK encode error (%s)", msdk_status_to_string (status)));
857 break;
858 }
859
860 if (task->sync_point) {
861 thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks;
862 } else if (status == MFX_ERR_MORE_DATA) {
863 break;
864 }
865 };
866
867 t = thiz->next_task;
868 for (i = 0; i < thiz->num_tasks; i++) {
869 gst_msdkenc_finish_frame (thiz, &thiz->tasks[t], discard);
870 t = (t + 1) % thiz->num_tasks;
871 }
872 }
873
874 static gboolean
gst_msdkenc_set_src_caps(GstMsdkEnc * thiz)875 gst_msdkenc_set_src_caps (GstMsdkEnc * thiz)
876 {
877 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
878 GstCaps *outcaps = NULL;
879 GstVideoCodecState *state;
880 GstTagList *tags;
881
882 if (klass->set_src_caps)
883 outcaps = klass->set_src_caps (thiz);
884
885 if (!outcaps)
886 return FALSE;
887
888 state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (thiz),
889 outcaps, thiz->input_state);
890 GST_DEBUG_OBJECT (thiz, "output caps: %" GST_PTR_FORMAT, state->caps);
891
892 gst_video_codec_state_unref (state);
893
894 tags = gst_tag_list_new_empty ();
895 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "msdkenc",
896 GST_TAG_MAXIMUM_BITRATE, thiz->bitrate * 1024,
897 GST_TAG_NOMINAL_BITRATE, thiz->bitrate * 1024, NULL);
898 gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (thiz), tags,
899 GST_TAG_MERGE_REPLACE);
900 gst_tag_list_unref (tags);
901
902 return TRUE;
903 }
904
905 static GstBufferPool *
gst_msdkenc_create_buffer_pool(GstMsdkEnc * thiz,GstCaps * caps,guint num_buffers,gboolean set_align)906 gst_msdkenc_create_buffer_pool (GstMsdkEnc * thiz, GstCaps * caps,
907 guint num_buffers, gboolean set_align)
908 {
909 GstBufferPool *pool = NULL;
910 GstStructure *config;
911 GstAllocator *allocator = NULL;
912 GstVideoInfo info;
913 GstVideoAlignment align;
914 GstAllocationParams params = { 0, 31, 0, 0, };
915 mfxFrameAllocResponse *alloc_resp = NULL;
916
917 if (thiz->has_vpp)
918 alloc_resp = set_align ? &thiz->vpp_alloc_resp : &thiz->alloc_resp;
919 else
920 alloc_resp = &thiz->alloc_resp;
921
922 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
923 if (!pool)
924 goto error_no_pool;
925
926 if (!gst_video_info_from_caps (&info, caps)) {
927 GST_INFO_OBJECT (thiz, "failed to get video info");
928 return NULL;
929 }
930
931 gst_msdk_set_video_alignment (&info, &align);
932 gst_video_info_align (&info, &align);
933
934 if (thiz->use_dmabuf)
935 allocator =
936 gst_msdk_dmabuf_allocator_new (thiz->context, &info, alloc_resp);
937 else if (thiz->use_video_memory)
938 allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp);
939 else
940 allocator = gst_msdk_system_allocator_new (&info);
941
942 if (!allocator)
943 goto error_no_allocator;
944
945 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
946 gst_buffer_pool_config_set_params (config, caps, info.size, num_buffers, 0);
947 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
948 gst_buffer_pool_config_add_option (config,
949 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
950
951 if (thiz->use_video_memory) {
952 gst_buffer_pool_config_add_option (config,
953 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
954 if (thiz->use_dmabuf)
955 gst_buffer_pool_config_add_option (config,
956 GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
957 }
958
959 gst_buffer_pool_config_set_video_alignment (config, &align);
960 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
961 gst_object_unref (allocator);
962
963 if (!gst_buffer_pool_set_config (pool, config))
964 goto error_pool_config;
965
966 if (set_align)
967 thiz->aligned_info = info;
968
969 return pool;
970
971 error_no_pool:
972 {
973 GST_INFO_OBJECT (thiz, "failed to create bufferpool");
974 return NULL;
975 }
976 error_no_allocator:
977 {
978 GST_INFO_OBJECT (thiz, "failed to create allocator");
979 gst_object_unref (pool);
980 return NULL;
981 }
982 error_pool_config:
983 {
984 GST_INFO_OBJECT (thiz, "failed to set config");
985 gst_object_unref (pool);
986 gst_object_unref (allocator);
987 return NULL;
988 }
989 }
990
991 /* Fixme: Common routine used by all msdk elements, should be
992 * moved to a common util file */
993 static gboolean
_gst_caps_has_feature(const GstCaps * caps,const gchar * feature)994 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
995 {
996 guint i;
997
998 for (i = 0; i < gst_caps_get_size (caps); i++) {
999 GstCapsFeatures *const features = gst_caps_get_features (caps, i);
1000 /* Skip ANY features, we need an exact match for correct evaluation */
1001 if (gst_caps_features_is_any (features))
1002 continue;
1003 if (gst_caps_features_contains (features, feature))
1004 return TRUE;
1005 }
1006 return FALSE;
1007 }
1008
1009 static gboolean
sinkpad_can_dmabuf(GstMsdkEnc * thiz)1010 sinkpad_can_dmabuf (GstMsdkEnc * thiz)
1011 {
1012 gboolean ret = FALSE;
1013 GstCaps *caps, *allowed_caps;
1014 GstPad *sinkpad;
1015
1016 sinkpad = GST_VIDEO_ENCODER_SINK_PAD (thiz);
1017 caps = gst_pad_get_pad_template_caps (sinkpad);
1018
1019 allowed_caps = gst_pad_peer_query_caps (sinkpad, caps);
1020 if (!allowed_caps)
1021 goto done;
1022 if (gst_caps_is_any (allowed_caps) || gst_caps_is_empty (allowed_caps)
1023 || allowed_caps == caps)
1024 goto done;
1025
1026 if (_gst_caps_has_feature (allowed_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
1027 ret = TRUE;
1028
1029 done:
1030 if (caps)
1031 gst_caps_unref (caps);
1032 if (allowed_caps)
1033 gst_caps_unref (allowed_caps);
1034 return ret;
1035 }
1036
1037 static gboolean
gst_msdkenc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)1038 gst_msdkenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
1039 {
1040 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1041 GstMsdkEncClass *klass = GST_MSDKENC_GET_CLASS (thiz);
1042
1043 if (state) {
1044 if (thiz->input_state)
1045 gst_video_codec_state_unref (thiz->input_state);
1046 thiz->input_state = gst_video_codec_state_ref (state);
1047 }
1048
1049 /* TODO: Currently d3d allocator is not implemented.
1050 * So encoder uses system memory by default on Windows.
1051 */
1052 #ifndef _WIN32
1053 thiz->use_video_memory = TRUE;
1054 #else
1055 thiz->use_video_memory = FALSE;
1056 #endif
1057
1058 GST_INFO_OBJECT (encoder, "This MSDK encoder uses %s memory",
1059 thiz->use_video_memory ? "video" : "system");
1060
1061 if (klass->set_format) {
1062 if (!klass->set_format (thiz))
1063 return FALSE;
1064 }
1065
1066 /* If upstream supports DMABufCapsfeatures, then we request for the dmabuf
1067 * based pipeline usage. Ideally we should have dmabuf support even with
1068 * raw-caps negotiation, but we don't have dmabuf-import support in msdk
1069 * plugin yet */
1070 if (sinkpad_can_dmabuf (thiz)) {
1071 thiz->input_state->caps = gst_caps_make_writable (thiz->input_state->caps);
1072 gst_caps_set_features (thiz->input_state->caps, 0,
1073 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
1074 thiz->use_dmabuf = TRUE;
1075 }
1076
1077 if (!gst_msdkenc_init_encoder (thiz))
1078 return FALSE;
1079
1080 if (!gst_msdkenc_set_src_caps (thiz)) {
1081 gst_msdkenc_close_encoder (thiz);
1082 return FALSE;
1083 }
1084
1085 if (!thiz->msdk_pool) {
1086 guint num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1087 thiz->msdk_pool =
1088 gst_msdkenc_create_buffer_pool (thiz, thiz->input_state->caps,
1089 num_buffers, TRUE);
1090 }
1091
1092 gst_msdkenc_set_latency (thiz);
1093
1094 /* Create another bufferpool if VPP requires */
1095 if (thiz->has_vpp) {
1096 GstVideoInfo *info = &thiz->input_state->info;
1097 GstVideoInfo nv12_info;
1098 GstCaps *caps;
1099 GstBufferPool *pool = NULL;
1100
1101 gst_video_info_init (&nv12_info);
1102 gst_video_info_set_format (&nv12_info, GST_VIDEO_FORMAT_NV12, info->width,
1103 info->height);
1104 caps = gst_video_info_to_caps (&nv12_info);
1105
1106 pool =
1107 gst_msdkenc_create_buffer_pool (thiz, caps, thiz->num_surfaces, FALSE);
1108
1109 thiz->msdk_converted_pool = pool;
1110 gst_caps_unref (caps);
1111 }
1112
1113 return TRUE;
1114 }
1115
1116 static MsdkSurface *
gst_msdkenc_get_surface_from_pool(GstMsdkEnc * thiz,GstBufferPool * pool,GstBufferPoolAcquireParams * params)1117 gst_msdkenc_get_surface_from_pool (GstMsdkEnc * thiz, GstBufferPool * pool,
1118 GstBufferPoolAcquireParams * params)
1119 {
1120 GstBuffer *new_buffer;
1121 mfxFrameSurface1 *new_surface;
1122 MsdkSurface *msdk_surface;
1123
1124 if (!gst_buffer_pool_is_active (pool) &&
1125 !gst_buffer_pool_set_active (pool, TRUE)) {
1126 GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
1127 return NULL;
1128 }
1129
1130 if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
1131 GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
1132 return NULL;
1133 }
1134
1135 if (gst_msdk_is_msdk_buffer (new_buffer))
1136 new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
1137 else {
1138 GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
1139 return NULL;
1140 }
1141
1142 msdk_surface = gst_msdkenc_create_surface (new_surface, new_buffer);
1143
1144 return msdk_surface;
1145 }
1146
1147 #ifndef _WIN32
1148 static gboolean
import_dmabuf_to_msdk_surface(GstMsdkEnc * thiz,GstBuffer * buf,MsdkSurface * msdk_surface)1149 import_dmabuf_to_msdk_surface (GstMsdkEnc * thiz, GstBuffer * buf,
1150 MsdkSurface * msdk_surface)
1151 {
1152 GstMemory *mem = NULL;
1153 GstVideoInfo vinfo;
1154 GstVideoMeta *vmeta;
1155 GstMsdkMemoryID *msdk_mid = NULL;
1156 mfxFrameSurface1 *mfx_surface = NULL;
1157 gint fd, i;
1158 mem = gst_buffer_peek_memory (buf, 0);
1159 fd = gst_dmabuf_memory_get_fd (mem);
1160 if (fd < 0)
1161 return FALSE;
1162
1163 vinfo = thiz->input_state->info;
1164 /* Update offset/stride/size if there is VideoMeta attached to
1165 * the buffer */
1166 vmeta = gst_buffer_get_video_meta (buf);
1167 if (vmeta) {
1168 if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
1169 GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
1170 GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
1171 GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
1172 GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
1173 "the negotiated width/height/format");
1174 return FALSE;
1175 }
1176 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
1177 GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
1178 GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
1179 }
1180 GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
1181 }
1182
1183 /* Upstream neither accepted the msdk pool nor the msdk buffer size restrictions.
1184 * Current media-driver and GMMLib will fail due to strict memory size restrictions.
1185 * Ideally, media-driver should accept what ever memory coming from other drivers
1186 * in case of dmabuf-import and this is how the intel-vaapi-driver works.
1187 * For now, in order to avoid any crash we check the buffer size and fallback
1188 * to copy frame method.
1189 *
1190 * See this: https://github.com/intel/media-driver/issues/169
1191 * */
1192 if (GST_VIDEO_INFO_SIZE (&vinfo) < GST_VIDEO_INFO_SIZE (&thiz->aligned_info))
1193 return FALSE;
1194
1195 mfx_surface = msdk_surface->surface;
1196 msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;
1197
1198 /* release the internal memory storage of associated mfxSurface */
1199 gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID);
1200
1201 /* export dmabuf to vasurface */
1202 if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd,
1203 msdk_mid->surface))
1204 return FALSE;
1205
1206 return TRUE;
1207 }
1208 #endif
1209
1210 static MsdkSurface *
gst_msdkenc_get_surface_from_frame(GstMsdkEnc * thiz,GstVideoCodecFrame * frame)1211 gst_msdkenc_get_surface_from_frame (GstMsdkEnc * thiz,
1212 GstVideoCodecFrame * frame)
1213 {
1214 GstVideoFrame src_frame, out_frame;
1215 MsdkSurface *msdk_surface;
1216 GstBuffer *inbuf;
1217 GstMemory *mem = NULL;
1218
1219 inbuf = frame->input_buffer;
1220 if (gst_msdk_is_msdk_buffer (inbuf)) {
1221 msdk_surface = g_slice_new0 (MsdkSurface);
1222 msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
1223 return msdk_surface;
1224 }
1225
1226 /* If upstream hasn't accpeted the proposed msdk bufferpool,
1227 * just copy frame (if not dmabuf backed )to msdk buffer and take a surface from it.
1228 */
1229 if (!(msdk_surface =
1230 gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_pool, NULL)))
1231 goto error;
1232
1233 #ifndef _WIN32
1234 /************ dmabuf-import ************* */
1235 /* if upstream provided a dmabuf backed memory, but not an msdk
1236 * buffer, we could try to export the dmabuf to underlined vasurface */
1237 mem = gst_buffer_peek_memory (inbuf, 0);
1238 if (gst_is_dmabuf_memory (mem)) {
1239 if (import_dmabuf_to_msdk_surface (thiz, inbuf, msdk_surface))
1240 return msdk_surface;
1241 else
1242 GST_INFO_OBJECT (thiz, "Upstream dmabuf-backed memory is not imported"
1243 "to the msdk surface, fall back to the copy input frame method");
1244 }
1245 #endif
1246
1247 if (!gst_video_frame_map (&src_frame, &thiz->input_state->info, inbuf,
1248 GST_MAP_READ)) {
1249 GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
1250 goto error;
1251 }
1252
1253 if (!gst_video_frame_map (&out_frame, &thiz->aligned_info, msdk_surface->buf,
1254 GST_MAP_WRITE)) {
1255 GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
1256 gst_video_frame_unmap (&src_frame);
1257 goto error;
1258 }
1259
1260 if (!gst_video_frame_copy (&out_frame, &src_frame)) {
1261 GST_ERROR_OBJECT (thiz, "failed to copy frame");
1262 gst_video_frame_unmap (&out_frame);
1263 gst_video_frame_unmap (&src_frame);
1264 goto error;
1265 }
1266
1267 gst_video_frame_unmap (&out_frame);
1268 gst_video_frame_unmap (&src_frame);
1269
1270 gst_buffer_replace (&frame->input_buffer, msdk_surface->buf);
1271 gst_buffer_unref (msdk_surface->buf);
1272 msdk_surface->buf = NULL;
1273
1274 return msdk_surface;
1275
1276 error:
1277 if (msdk_surface) {
1278 if (msdk_surface->buf)
1279 gst_buffer_unref (msdk_surface->buf);
1280 g_slice_free (MsdkSurface, msdk_surface);
1281 }
1282 return NULL;
1283 }
1284
1285 static GstFlowReturn
gst_msdkenc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)1286 gst_msdkenc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1287 {
1288 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1289 GstVideoInfo *info = &thiz->input_state->info;
1290 FrameData *fdata;
1291 MsdkSurface *surface;
1292
1293 if (thiz->reconfig) {
1294 gst_msdkenc_flush_frames (thiz, FALSE);
1295 gst_msdkenc_set_format (encoder, NULL);
1296 }
1297
1298 if (G_UNLIKELY (thiz->context == NULL))
1299 goto not_inited;
1300
1301 if (thiz->has_vpp) {
1302 MsdkSurface *vpp_surface;
1303 GstVideoFrame vframe;
1304 mfxSession session;
1305 mfxSyncPoint vpp_sync_point = NULL;
1306 mfxStatus status;
1307
1308 vpp_surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1309 if (!vpp_surface)
1310 goto invalid_surface;
1311 surface =
1312 gst_msdkenc_get_surface_from_pool (thiz, thiz->msdk_converted_pool,
1313 NULL);
1314 if (!surface)
1315 goto invalid_surface;
1316
1317 if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
1318 goto invalid_frame;
1319
1320 if (frame->pts != GST_CLOCK_TIME_NONE) {
1321 vpp_surface->surface->Data.TimeStamp =
1322 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1323 surface->surface->Data.TimeStamp =
1324 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1325 } else {
1326 vpp_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1327 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1328 }
1329
1330 session = gst_msdk_context_get_session (thiz->context);
1331 for (;;) {
1332 status =
1333 MFXVideoVPP_RunFrameVPPAsync (session, vpp_surface->surface,
1334 surface->surface, NULL, &vpp_sync_point);
1335 if (status != MFX_WRN_DEVICE_BUSY)
1336 break;
1337 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1338 g_usleep (1000);
1339 };
1340
1341 gst_video_frame_unmap (&vframe);
1342
1343 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1344 GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Converting frame failed."),
1345 ("MSDK VPP error (%s)", msdk_status_to_string (status)));
1346 gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame);
1347 return GST_FLOW_ERROR;
1348 }
1349
1350 fdata = g_slice_new0 (FrameData);
1351 fdata->frame = gst_video_codec_frame_ref (frame);
1352 fdata->frame_surface = vpp_surface;
1353 fdata->converted_surface = surface;
1354
1355 thiz->pending_frames = g_list_prepend (thiz->pending_frames, fdata);
1356 } else {
1357 surface = gst_msdkenc_get_surface_from_frame (thiz, frame);
1358 if (!surface)
1359 goto invalid_surface;
1360
1361 fdata = gst_msdkenc_queue_frame (thiz, frame, info);
1362 if (!fdata)
1363 goto invalid_frame;
1364
1365 fdata->frame_surface = surface;
1366
1367 if (frame->pts != GST_CLOCK_TIME_NONE) {
1368 surface->surface->Data.TimeStamp =
1369 gst_util_uint64_scale (frame->pts, 90000, GST_SECOND);
1370 } else {
1371 surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
1372 }
1373 }
1374
1375 return gst_msdkenc_encode_frame (thiz, surface->surface, frame);
1376
1377 /* ERRORS */
1378 not_inited:
1379 {
1380 GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1381 return GST_FLOW_NOT_NEGOTIATED;
1382 }
1383 invalid_surface:
1384 {
1385 GST_ERROR_OBJECT (encoder, "Surface pool is full");
1386 return GST_FLOW_ERROR;
1387 }
1388 invalid_frame:
1389 {
1390 GST_WARNING_OBJECT (encoder, "Failed to map frame");
1391 return GST_FLOW_OK;
1392 }
1393 }
1394
1395 static gboolean
gst_msdkenc_start(GstVideoEncoder * encoder)1396 gst_msdkenc_start (GstVideoEncoder * encoder)
1397 {
1398 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1399
1400 if (gst_msdk_context_prepare (GST_ELEMENT_CAST (thiz), &thiz->context)) {
1401 GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
1402 thiz->context);
1403
1404 if (gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_ENCODER) {
1405 GstMsdkContext *parent_context, *msdk_context;
1406
1407 parent_context = thiz->context;
1408 msdk_context = gst_msdk_context_new_with_parent (parent_context);
1409
1410 if (!msdk_context) {
1411 GST_ERROR_OBJECT (thiz, "Context creation failed");
1412 return FALSE;
1413 }
1414
1415 thiz->context = msdk_context;
1416 gst_object_unref (parent_context);
1417
1418 GST_INFO_OBJECT (thiz,
1419 "Creating new context %" GST_PTR_FORMAT " with joined session",
1420 thiz->context);
1421 } else {
1422 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_ENCODER);
1423 }
1424 } else {
1425 if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
1426 thiz->hardware, GST_MSDK_JOB_ENCODER))
1427 return FALSE;
1428 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
1429 thiz->context);
1430 }
1431
1432 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
1433
1434 /* Set the minimum pts to some huge value (1000 hours). This keeps
1435 the dts at the start of the stream from needing to be
1436 negative. */
1437 gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
1438
1439 return TRUE;
1440 }
1441
1442 static gboolean
gst_msdkenc_stop(GstVideoEncoder * encoder)1443 gst_msdkenc_stop (GstVideoEncoder * encoder)
1444 {
1445 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1446
1447 gst_msdkenc_flush_frames (thiz, TRUE);
1448 gst_msdkenc_close_encoder (thiz);
1449 gst_msdkenc_dequeue_all_frames (thiz);
1450
1451 if (thiz->input_state)
1452 gst_video_codec_state_unref (thiz->input_state);
1453 thiz->input_state = NULL;
1454
1455 gst_object_replace ((GstObject **) & thiz->context, NULL);
1456
1457 return TRUE;
1458 }
1459
1460 static gboolean
gst_msdkenc_flush(GstVideoEncoder * encoder)1461 gst_msdkenc_flush (GstVideoEncoder * encoder)
1462 {
1463 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1464
1465 gst_msdkenc_flush_frames (thiz, TRUE);
1466 gst_msdkenc_close_encoder (thiz);
1467 gst_msdkenc_dequeue_all_frames (thiz);
1468
1469 gst_msdkenc_init_encoder (thiz);
1470
1471 return TRUE;
1472 }
1473
1474 static GstFlowReturn
gst_msdkenc_finish(GstVideoEncoder * encoder)1475 gst_msdkenc_finish (GstVideoEncoder * encoder)
1476 {
1477 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1478
1479 gst_msdkenc_flush_frames (thiz, FALSE);
1480
1481 return GST_FLOW_OK;
1482 }
1483
1484
1485 static gboolean
gst_msdkenc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)1486 gst_msdkenc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1487 {
1488 GstMsdkEnc *thiz = GST_MSDKENC (encoder);
1489 GstVideoInfo info;
1490 GstBufferPool *pool = NULL;
1491 GstAllocator *allocator = NULL;
1492 GstCaps *caps;
1493 guint num_buffers;
1494
1495 if (!thiz->input_state)
1496 return FALSE;
1497
1498 gst_query_parse_allocation (query, &caps, NULL);
1499
1500 if (!caps) {
1501 GST_INFO_OBJECT (encoder, "failed to get caps");
1502 return FALSE;
1503 }
1504
1505 if (!gst_video_info_from_caps (&info, caps)) {
1506 GST_INFO_OBJECT (encoder, "failed to get video info");
1507 return FALSE;
1508 }
1509
1510 /* if upstream allocation query supports dmabuf-capsfeatures,
1511 * we do allocate dmabuf backed memory */
1512 if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
1513 GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory");
1514 thiz->use_dmabuf = TRUE;
1515 }
1516
1517 num_buffers = gst_msdkenc_maximum_delayed_frames (thiz) + 1;
1518 pool = gst_msdkenc_create_buffer_pool (thiz, caps, num_buffers, TRUE);
1519
1520 gst_query_add_allocation_pool (query, pool, GST_VIDEO_INFO_SIZE (&info),
1521 num_buffers, 0);
1522 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1523
1524 if (pool) {
1525 GstStructure *config;
1526 GstAllocationParams params = { 0, 31, 0, 0, };
1527
1528 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1529
1530 if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
1531 gst_query_add_allocation_param (query, allocator, ¶ms);
1532 gst_structure_free (config);
1533 }
1534
1535 gst_object_unref (pool);
1536
1537 return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
1538 query);
1539 }
1540
1541
1542 static void
gst_msdkenc_finalize(GObject * object)1543 gst_msdkenc_finalize (GObject * object)
1544 {
1545 GstMsdkEnc *thiz = GST_MSDKENC (object);
1546
1547 if (thiz->input_state)
1548 gst_video_codec_state_unref (thiz->input_state);
1549 thiz->input_state = NULL;
1550
1551 gst_object_replace ((GstObject **) & thiz->msdk_pool, NULL);
1552 gst_object_replace ((GstObject **) & thiz->msdk_converted_pool, NULL);
1553
1554 G_OBJECT_CLASS (parent_class)->finalize (object);
1555 }
1556
1557 static void
gst_msdkenc_class_init(GstMsdkEncClass * klass)1558 gst_msdkenc_class_init (GstMsdkEncClass * klass)
1559 {
1560 GObjectClass *gobject_class;
1561 GstElementClass *element_class;
1562 GstVideoEncoderClass *gstencoder_class;
1563
1564 gobject_class = G_OBJECT_CLASS (klass);
1565 element_class = GST_ELEMENT_CLASS (klass);
1566 gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
1567
1568 gobject_class->finalize = gst_msdkenc_finalize;
1569
1570 element_class->set_context = gst_msdkenc_set_context;
1571
1572 gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkenc_set_format);
1573 gstencoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkenc_handle_frame);
1574 gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkenc_start);
1575 gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkenc_stop);
1576 gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkenc_flush);
1577 gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkenc_finish);
1578 gstencoder_class->propose_allocation =
1579 GST_DEBUG_FUNCPTR (gst_msdkenc_propose_allocation);
1580
1581 gst_element_class_add_static_pad_template (element_class, &sink_factory);
1582 }
1583
1584 static void
gst_msdkenc_init(GstMsdkEnc * thiz)1585 gst_msdkenc_init (GstMsdkEnc * thiz)
1586 {
1587 thiz->hardware = PROP_HARDWARE_DEFAULT;
1588 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1589 thiz->target_usage = PROP_TARGET_USAGE_DEFAULT;
1590 thiz->rate_control = PROP_RATE_CONTROL_DEFAULT;
1591 thiz->bitrate = PROP_BITRATE_DEFAULT;
1592 thiz->max_frame_size = PROP_MAX_FRAME_SIZE_DEFAULT;
1593 thiz->max_vbv_bitrate = PROP_MAX_VBV_BITRATE_DEFAULT;
1594 thiz->accuracy = PROP_AVBR_ACCURACY_DEFAULT;
1595 thiz->convergence = PROP_AVBR_ACCURACY_DEFAULT;
1596 thiz->lookahead_depth = PROP_RC_LOOKAHEAD_DEPTH_DEFAULT;
1597 thiz->qpi = PROP_QPI_DEFAULT;
1598 thiz->qpp = PROP_QPP_DEFAULT;
1599 thiz->qpb = PROP_QPB_DEFAULT;
1600 thiz->gop_size = PROP_GOP_SIZE_DEFAULT;
1601 thiz->ref_frames = PROP_REF_FRAMES_DEFAULT;
1602 thiz->i_frames = PROP_I_FRAMES_DEFAULT;
1603 thiz->b_frames = PROP_B_FRAMES_DEFAULT;
1604 thiz->num_slices = PROP_NUM_SLICES_DEFAULT;
1605 thiz->mbbrc = PROP_MBBRC_DEFAULT;
1606 thiz->adaptive_i = PROP_ADAPTIVE_I_DEFAULT;
1607 thiz->adaptive_b = PROP_ADAPTIVE_B_DEFAULT;
1608 }
1609
1610 /* gst_msdkenc_set_common_property:
1611 *
1612 * This is a helper function to set the common property
1613 * of base encoder from subclass implementation.
1614 */
1615 gboolean
gst_msdkenc_set_common_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1616 gst_msdkenc_set_common_property (GObject * object, guint prop_id,
1617 const GValue * value, GParamSpec * pspec)
1618 {
1619 GstMsdkEnc *thiz = GST_MSDKENC (object);
1620 GstState state;
1621 gboolean ret = TRUE;
1622
1623 GST_OBJECT_LOCK (thiz);
1624
1625 state = GST_STATE (thiz);
1626 if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1627 !(pspec->flags & GST_PARAM_MUTABLE_PLAYING)) {
1628 ret = FALSE;
1629 goto wrong_state;
1630 }
1631
1632 switch (prop_id) {
1633 case GST_MSDKENC_PROP_HARDWARE:
1634 thiz->hardware = g_value_get_boolean (value);
1635 break;
1636 case GST_MSDKENC_PROP_ASYNC_DEPTH:
1637 thiz->async_depth = g_value_get_uint (value);
1638 break;
1639 case GST_MSDKENC_PROP_TARGET_USAGE:
1640 thiz->target_usage = g_value_get_uint (value);
1641 break;
1642 case GST_MSDKENC_PROP_RATE_CONTROL:
1643 thiz->rate_control = g_value_get_enum (value);
1644 break;
1645 case GST_MSDKENC_PROP_BITRATE:
1646 thiz->bitrate = g_value_get_uint (value);
1647 thiz->reconfig = TRUE;
1648 break;
1649 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
1650 thiz->max_frame_size = g_value_get_uint (value);
1651 break;
1652 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
1653 thiz->max_vbv_bitrate = g_value_get_uint (value);
1654 break;
1655 case GST_MSDKENC_PROP_AVBR_ACCURACY:
1656 thiz->accuracy = g_value_get_uint (value);
1657 break;
1658 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
1659 thiz->convergence = g_value_get_uint (value);
1660 break;
1661 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
1662 thiz->lookahead_depth = g_value_get_uint (value);
1663 break;
1664 case GST_MSDKENC_PROP_QPI:
1665 thiz->qpi = g_value_get_uint (value);
1666 break;
1667 case GST_MSDKENC_PROP_QPP:
1668 thiz->qpp = g_value_get_uint (value);
1669 break;
1670 case GST_MSDKENC_PROP_QPB:
1671 thiz->qpb = g_value_get_uint (value);
1672 break;
1673 case GST_MSDKENC_PROP_GOP_SIZE:
1674 thiz->gop_size = g_value_get_uint (value);
1675 break;
1676 case GST_MSDKENC_PROP_REF_FRAMES:
1677 thiz->ref_frames = g_value_get_uint (value);
1678 break;
1679 case GST_MSDKENC_PROP_I_FRAMES:
1680 thiz->i_frames = g_value_get_uint (value);
1681 break;
1682 case GST_MSDKENC_PROP_B_FRAMES:
1683 thiz->b_frames = g_value_get_uint (value);
1684 break;
1685 case GST_MSDKENC_PROP_NUM_SLICES:
1686 thiz->num_slices = g_value_get_uint (value);
1687 break;
1688 case GST_MSDKENC_PROP_MBBRC:
1689 thiz->mbbrc = g_value_get_enum (value);
1690 break;
1691 case GST_MSDKENC_PROP_ADAPTIVE_I:
1692 thiz->adaptive_i = g_value_get_enum (value);
1693 break;
1694 case GST_MSDKENC_PROP_ADAPTIVE_B:
1695 thiz->adaptive_b = g_value_get_enum (value);
1696 break;
1697 default:
1698 ret = FALSE;
1699 break;
1700 }
1701 GST_OBJECT_UNLOCK (thiz);
1702 return ret;
1703
1704 /* ERROR */
1705 wrong_state:
1706 {
1707 GST_WARNING_OBJECT (thiz, "setting property in wrong state");
1708 GST_OBJECT_UNLOCK (thiz);
1709 return ret;
1710 }
1711 }
1712
1713 /* gst_msdkenc_get_common_property:
1714 *
1715 * This is a helper function to get the common property
1716 * of base encoder from subclass implementation.
1717 */
1718 gboolean
gst_msdkenc_get_common_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1719 gst_msdkenc_get_common_property (GObject * object, guint prop_id,
1720 GValue * value, GParamSpec * pspec)
1721 {
1722 GstMsdkEnc *thiz = GST_MSDKENC (object);
1723 gboolean ret = TRUE;
1724
1725 GST_OBJECT_LOCK (thiz);
1726 switch (prop_id) {
1727 case GST_MSDKENC_PROP_HARDWARE:
1728 g_value_set_boolean (value, thiz->hardware);
1729 break;
1730 case GST_MSDKENC_PROP_ASYNC_DEPTH:
1731 g_value_set_uint (value, thiz->async_depth);
1732 break;
1733 case GST_MSDKENC_PROP_TARGET_USAGE:
1734 g_value_set_uint (value, thiz->target_usage);
1735 break;
1736 case GST_MSDKENC_PROP_RATE_CONTROL:
1737 g_value_set_enum (value, thiz->rate_control);
1738 break;
1739 case GST_MSDKENC_PROP_BITRATE:
1740 g_value_set_uint (value, thiz->bitrate);
1741 break;
1742 case GST_MSDKENC_PROP_MAX_FRAME_SIZE:
1743 g_value_set_uint (value, thiz->max_frame_size);
1744 break;
1745 case GST_MSDKENC_PROP_MAX_VBV_BITRATE:
1746 g_value_set_uint (value, thiz->max_vbv_bitrate);
1747 break;
1748 case GST_MSDKENC_PROP_AVBR_ACCURACY:
1749 g_value_set_uint (value, thiz->accuracy);
1750 break;
1751 case GST_MSDKENC_PROP_AVBR_CONVERGENCE:
1752 g_value_set_uint (value, thiz->convergence);
1753 break;
1754 case GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH:
1755 g_value_set_uint (value, thiz->lookahead_depth);
1756 break;
1757 case GST_MSDKENC_PROP_QPI:
1758 g_value_set_uint (value, thiz->qpi);
1759 break;
1760 case GST_MSDKENC_PROP_QPP:
1761 g_value_set_uint (value, thiz->qpp);
1762 break;
1763 case GST_MSDKENC_PROP_QPB:
1764 g_value_set_uint (value, thiz->qpb);
1765 break;
1766 case GST_MSDKENC_PROP_GOP_SIZE:
1767 g_value_set_uint (value, thiz->gop_size);
1768 break;
1769 case GST_MSDKENC_PROP_REF_FRAMES:
1770 g_value_set_uint (value, thiz->ref_frames);
1771 break;
1772 case GST_MSDKENC_PROP_I_FRAMES:
1773 g_value_set_uint (value, thiz->i_frames);
1774 break;
1775 case GST_MSDKENC_PROP_B_FRAMES:
1776 g_value_set_uint (value, thiz->b_frames);
1777 break;
1778 case GST_MSDKENC_PROP_NUM_SLICES:
1779 g_value_set_uint (value, thiz->num_slices);
1780 break;
1781 case GST_MSDKENC_PROP_MBBRC:
1782 g_value_set_enum (value, thiz->mbbrc);
1783 break;
1784 case GST_MSDKENC_PROP_ADAPTIVE_I:
1785 g_value_set_enum (value, thiz->adaptive_i);
1786 break;
1787 case GST_MSDKENC_PROP_ADAPTIVE_B:
1788 g_value_set_enum (value, thiz->adaptive_b);
1789 break;
1790 default:
1791 ret = FALSE;
1792 break;
1793 }
1794 GST_OBJECT_UNLOCK (thiz);
1795 return ret;
1796 }
1797
1798 /* gst_msdkenc_install_common_properties:
1799 * @thiz: a #GstMsdkEnc
1800 *
1801 * This is a helper function to install common properties
1802 * of base encoder from subclass implementation.
1803 * Encoders like jpeg do't require all the common properties
1804 * and they can avoid installing it into base gobject.
1805 */
1806 void
gst_msdkenc_install_common_properties(GstMsdkEncClass * klass)1807 gst_msdkenc_install_common_properties (GstMsdkEncClass * klass)
1808 {
1809 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1810 GParamSpec *obj_properties[GST_MSDKENC_PROP_MAX] = { NULL, };
1811
1812 obj_properties[GST_MSDKENC_PROP_HARDWARE] =
1813 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware encoders",
1814 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1815
1816 obj_properties[GST_MSDKENC_PROP_ASYNC_DEPTH] =
1817 g_param_spec_uint ("async-depth", "Async Depth",
1818 "Depth of asynchronous pipeline",
1819 1, 20, PROP_ASYNC_DEPTH_DEFAULT,
1820 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1821
1822 obj_properties[GST_MSDKENC_PROP_TARGET_USAGE] =
1823 g_param_spec_uint ("target-usage", "Target Usage",
1824 "1: Best quality, 4: Balanced, 7: Best speed",
1825 1, 7, PROP_TARGET_USAGE_DEFAULT,
1826 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1827
1828 obj_properties[GST_MSDKENC_PROP_RATE_CONTROL] =
1829 g_param_spec_enum ("rate-control", "Rate Control",
1830 "Rate control method", gst_msdkenc_rate_control_get_type (),
1831 PROP_RATE_CONTROL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1832
1833 obj_properties[GST_MSDKENC_PROP_BITRATE] =
1834 g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
1835 2000 * 1024, PROP_BITRATE_DEFAULT,
1836 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING);
1837
1838 obj_properties[GST_MSDKENC_PROP_MAX_FRAME_SIZE] =
1839 g_param_spec_uint ("max-frame-size", "Max Frame Size",
1840 "Maximum possible size (in kb) of any compressed frames (0: auto-calculate)",
1841 0, G_MAXUINT16, PROP_MAX_FRAME_SIZE_DEFAULT,
1842 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1843
1844 /* Set the same upper bound with bitrate */
1845 obj_properties[GST_MSDKENC_PROP_MAX_VBV_BITRATE] =
1846 g_param_spec_uint ("max-vbv-bitrate", "Max VBV Bitrate",
1847 "Maximum bitrate(kbit/sec) at which data enters Video Buffering Verifier (0: auto-calculate)",
1848 0, 2000 * 1024, PROP_MAX_VBV_BITRATE_DEFAULT,
1849 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1850
1851 obj_properties[GST_MSDKENC_PROP_AVBR_ACCURACY] =
1852 g_param_spec_uint ("accuracy", "Accuracy", "The AVBR Accuracy in "
1853 "the unit of tenth of percent", 0, G_MAXUINT16,
1854 PROP_AVBR_ACCURACY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1855
1856 obj_properties[GST_MSDKENC_PROP_AVBR_CONVERGENCE] =
1857 g_param_spec_uint ("convergence", "Convergence",
1858 "The AVBR Convergence in the unit of 100 frames", 0, G_MAXUINT16,
1859 PROP_AVBR_CONVERGENCE_DEFAULT,
1860 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1861
1862 obj_properties[GST_MSDKENC_PROP_RC_LOOKAHEAD_DEPTH] =
1863 g_param_spec_uint ("rc-lookahead", "Look-ahead depth",
1864 "Number of frames to look ahead for Rate control", 10, 100,
1865 PROP_RC_LOOKAHEAD_DEPTH_DEFAULT,
1866 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1867
1868 obj_properties[GST_MSDKENC_PROP_QPI] =
1869 g_param_spec_uint ("qpi", "QPI",
1870 "Constant quantizer for I frames (0 unlimited). Also used as "
1871 "ICQQuality or QVBRQuality for different RateControl methods",
1872 0, 51, PROP_QPI_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1873
1874 obj_properties[GST_MSDKENC_PROP_QPP] =
1875 g_param_spec_uint ("qpp", "QPP",
1876 "Constant quantizer for P frames (0 unlimited)",
1877 0, 51, PROP_QPP_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1878
1879 obj_properties[GST_MSDKENC_PROP_QPB] =
1880 g_param_spec_uint ("qpb", "QPB",
1881 "Constant quantizer for B frames (0 unlimited)",
1882 0, 51, PROP_QPB_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1883
1884 obj_properties[GST_MSDKENC_PROP_GOP_SIZE] =
1885 g_param_spec_uint ("gop-size", "GOP Size", "GOP Size", 0,
1886 G_MAXINT, PROP_GOP_SIZE_DEFAULT,
1887 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1888
1889 obj_properties[GST_MSDKENC_PROP_REF_FRAMES] =
1890 g_param_spec_uint ("ref-frames", "Reference Frames",
1891 "Number of reference frames",
1892 0, G_MAXINT, PROP_REF_FRAMES_DEFAULT,
1893 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1894
1895 obj_properties[GST_MSDKENC_PROP_I_FRAMES] =
1896 g_param_spec_uint ("i-frames", "I Frames",
1897 "Number of I frames between IDR frames",
1898 0, G_MAXINT, PROP_I_FRAMES_DEFAULT,
1899 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1900
1901 obj_properties[GST_MSDKENC_PROP_B_FRAMES] =
1902 g_param_spec_uint ("b-frames", "B Frames",
1903 "Number of B frames between I and P frames",
1904 0, G_MAXINT, PROP_B_FRAMES_DEFAULT,
1905 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1906
1907 obj_properties[GST_MSDKENC_PROP_NUM_SLICES] =
1908 g_param_spec_uint ("num-slices", "Number of Slices",
1909 "Number of slices per frame, Zero tells the encoder to "
1910 "choose any slice partitioning allowed by the codec standard",
1911 0, G_MAXINT, PROP_NUM_SLICES_DEFAULT,
1912 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1913
1914 obj_properties[GST_MSDKENC_PROP_MBBRC] =
1915 g_param_spec_enum ("mbbrc", "MB level bitrate control",
1916 "Macroblock level bitrate control",
1917 gst_msdkenc_mbbrc_get_type (),
1918 PROP_MBBRC_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1919
1920 obj_properties[GST_MSDKENC_PROP_ADAPTIVE_I] =
1921 g_param_spec_enum ("i-adapt", "Adaptive I-Frame Insertion",
1922 "Adaptive I-Frame Insertion control",
1923 gst_msdkenc_adaptive_i_get_type (),
1924 PROP_ADAPTIVE_I_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1925
1926 obj_properties[GST_MSDKENC_PROP_ADAPTIVE_B] =
1927 g_param_spec_enum ("b-adapt", "Adaptive B-Frame Insertion",
1928 "Adaptive B-Frame Insertion control",
1929 gst_msdkenc_adaptive_b_get_type (),
1930 PROP_ADAPTIVE_B_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1931
1932 g_object_class_install_properties (gobject_class,
1933 GST_MSDKENC_PROP_MAX, obj_properties);
1934 }
1935