1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2016, Intel Corporation
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
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.
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.
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.
38 #include "gstmsdkdec.h"
39 #include "gstmsdkbufferpool.h"
40 #include "gstmsdkvideomemory.h"
41 #include "gstmsdksystemmemory.h"
42 #include "gstmsdkcontextutil.h"
44 GST_DEBUG_CATEGORY_EXTERN (gst_msdkdec_debug);
45 #define GST_CAT_DEFAULT gst_msdkdec_debug
47 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
50 GST_STATIC_CAPS (GST_MSDK_CAPS_STR ("NV12", "NV12"))
53 #define PROP_HARDWARE_DEFAULT TRUE
54 #define PROP_ASYNC_DEPTH_DEFAULT 1
56 #define IS_ALIGNED(i, n) (((i) & ((n)-1)) == 0)
58 #define GST_TO_MFX_TIME(time) ((time) == GST_CLOCK_TIME_NONE ? \
59 MFX_TIMESTAMP_UNKNOWN : gst_util_uint64_scale_round ((time), 9, 100000))
61 #define MFX_TO_GST_TIME(time) ((time) == MFX_TIMESTAMP_UNKNOWN ? \
62 GST_CLOCK_TIME_NONE : gst_util_uint64_scale_round ((time), 100000, 9))
64 #define MFX_TIME_IS_VALID(time) ((time) != MFX_TIMESTAMP_UNKNOWN)
66 #define gst_msdkdec_parent_class parent_class
67 G_DEFINE_TYPE (GstMsdkDec, gst_msdkdec, GST_TYPE_VIDEO_DECODER);
69 typedef struct _MsdkSurface
71 mfxFrameSurface1 *surface;
80 mfxSyncPoint sync_point;
85 static gboolean gst_msdkdec_drain (GstVideoDecoder * decoder);
86 static gboolean gst_msdkdec_flush (GstVideoDecoder * decoder);
87 static gboolean gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset);
90 gst_msdkdec_add_bs_extra_param (GstMsdkDec * thiz, mfxExtBuffer * param)
92 if (thiz->num_bs_extra_params < MAX_BS_EXTRA_PARAMS) {
93 thiz->bs_extra_params[thiz->num_bs_extra_params] = param;
94 thiz->num_bs_extra_params++;
99 gst_msdkdec_add_video_extra_param (GstMsdkDec * thiz, mfxExtBuffer * param)
101 if (thiz->num_video_extra_params < MAX_VIDEO_EXTRA_PARAMS) {
102 thiz->video_extra_params[thiz->num_video_extra_params] = param;
103 thiz->num_video_extra_params++;
107 static GstVideoCodecFrame *
108 gst_msdkdec_get_oldest_frame (GstVideoDecoder * decoder)
110 GstVideoCodecFrame *frame = NULL, *old_frame = NULL;
114 frames = gst_video_decoder_get_frames (decoder);
116 for (l = frames; l != NULL; l = l->next) {
117 GstVideoCodecFrame *f = l->data;
119 if (!GST_CLOCK_TIME_IS_VALID (f->pts)) {
121 ("Frame doesn't have a valid pts yet, Use gst_video_decoder_get_oldest_frame()"
122 "with out considering the PTS for selecting the frame to be finished");
123 old_frame = gst_video_decoder_get_oldest_frame (decoder);
127 if (!frame || frame->pts > f->pts)
137 GST_LOG_OBJECT (decoder,
138 "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
139 frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
140 gst_video_codec_frame_ref (frame);
144 gst_video_codec_frame_unref (old_frame);
146 g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
152 free_surface (MsdkSurface * s)
154 gst_buffer_unref (s->buf);
155 g_slice_free (MsdkSurface, s);
159 unmap_frame (GstMsdkDec * thiz, MsdkSurface * s)
161 if (s->copy.buffer) {
162 /* we allocate this buffer from down stream, we need ref-1 for it */
163 gst_buffer_unref (s->copy.buffer);
164 gst_video_frame_unmap (&s->copy);
165 s->copy.buffer = NULL;
168 if (s->data.buffer) {
169 gst_video_frame_unmap (&s->data);
170 s->data.buffer = NULL;
175 gst_msdkdec_free_unlocked_msdk_surfaces (GstMsdkDec * thiz)
178 MsdkSurface *surface;
180 for (l = thiz->locked_msdk_surfaces; l;) {
181 GList *next = l->next;
183 if (surface->surface->Data.Locked == 0) {
184 unmap_frame (thiz, surface);
185 free_surface (surface);
186 thiz->locked_msdk_surfaces =
187 g_list_delete_link (thiz->locked_msdk_surfaces, l);
194 allocate_output_buffer (GstMsdkDec * thiz, GstBuffer ** buffer)
197 GstVideoCodecFrame *frame;
198 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
200 frame = gst_msdkdec_get_oldest_frame (decoder);
202 if (GST_PAD_IS_FLUSHING (decoder->srcpad))
203 return GST_FLOW_FLUSHING;
205 return GST_FLOW_CUSTOM_SUCCESS;
208 if (!frame->output_buffer) {
209 /* Free un-unsed msdk surfaces firstly, hence the associated mfx
210 * surfaces will be moved from used list to available list */
211 gst_msdkdec_free_unlocked_msdk_surfaces (thiz);
213 flow = gst_video_decoder_allocate_output_frame (decoder, frame);
214 if (flow != GST_FLOW_OK) {
215 gst_video_codec_frame_unref (frame);
220 *buffer = gst_buffer_ref (frame->output_buffer);
221 gst_buffer_replace (&frame->output_buffer, NULL);
222 gst_video_codec_frame_unref (frame);
228 get_surface (GstMsdkDec * thiz, GstBuffer * buffer)
231 GstVideoCodecState *output_state = NULL;
234 i = g_slice_new0 (MsdkSurface);
236 if (gst_msdk_is_msdk_buffer (buffer)) {
237 i->surface = gst_msdk_get_surface_from_buffer (buffer);
240 /* Confirm to activate the side pool */
241 if (!gst_buffer_pool_is_active (thiz->pool) &&
242 !gst_buffer_pool_set_active (thiz->pool, TRUE)) {
243 g_slice_free (MsdkSurface, i);
247 if (!gst_video_frame_map (&i->copy, &thiz->non_msdk_pool_info, buffer,
249 goto failed_unref_buffer;
251 if (gst_buffer_pool_acquire_buffer (thiz->pool, &buffer,
252 NULL) != GST_FLOW_OK)
253 goto failed_unmap_copy;
255 i->surface = gst_msdk_get_surface_from_buffer (buffer);
259 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
261 gst_video_frame_map (&i->data, &output_state->info, buffer,
263 gst_video_codec_state_unref (output_state);
265 goto failed_unref_buffer2;
269 gst_msdk_update_mfx_frame_info_from_mfx_video_param (&i->surface->Info,
272 thiz->locked_msdk_surfaces = g_list_append (thiz->locked_msdk_surfaces, i);
275 failed_unref_buffer2:
276 gst_buffer_unref (buffer);
277 buffer = i->data.buffer;
279 gst_video_frame_unmap (&i->copy);
281 gst_buffer_unref (buffer);
282 g_slice_free (MsdkSurface, i);
284 GST_ERROR_OBJECT (thiz, "failed to handle buffer");
289 gst_msdkdec_close_decoder (GstMsdkDec * thiz, gboolean reset_param)
293 if (!thiz->context || !thiz->initialized)
296 GST_DEBUG_OBJECT (thiz, "Closing decoder with context %" GST_PTR_FORMAT,
299 if (thiz->use_video_memory)
300 gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
302 status = MFXVideoDECODE_Close (gst_msdk_context_get_session (thiz->context));
303 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
304 GST_WARNING_OBJECT (thiz, "Decoder close failed (%s)",
305 msdk_status_to_string (status));
308 g_array_set_size (thiz->tasks, 0);
311 memset (&thiz->param, 0, sizeof (thiz->param));
313 thiz->num_bs_extra_params = 0;
314 thiz->num_video_extra_params = 0;
315 thiz->initialized = FALSE;
316 gst_adapter_clear (thiz->adapter);
320 gst_msdkdec_set_context (GstElement * element, GstContext * context)
322 GstMsdkContext *msdk_context = NULL;
323 GstMsdkDec *thiz = GST_MSDKDEC (element);
325 if (gst_msdk_context_get_context (context, &msdk_context)) {
326 gst_object_replace ((GstObject **) & thiz->context,
327 (GstObject *) msdk_context);
328 gst_object_unref (msdk_context);
331 if (gst_msdk_context_from_external_va_display (context,
332 thiz->hardware, 0 /* GST_MSDK_JOB_DECODER will be set later */ ,
334 gst_object_replace ((GstObject **) & thiz->context,
335 (GstObject *) msdk_context);
336 gst_object_unref (msdk_context);
339 if (gst_msdk_context_from_external_d3d11_device (context,
340 thiz->hardware, 0 /* GST_MSDK_JOB_DECODER will be set later */ ,
342 gst_object_replace ((GstObject **) & thiz->context,
343 (GstObject *) msdk_context);
344 gst_object_unref (msdk_context);
348 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
352 gst_msdkdec_init_decoder (GstMsdkDec * thiz)
354 GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
355 GstVideoInfo *info, *output_info;
358 mfxFrameAllocRequest request;
359 #if (MFX_VERSION >= 1022)
360 mfxExtDecVideoProcessing ext_dec_video_proc;
363 GstVideoCodecState *output_state =
364 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
366 if (thiz->initialized)
369 if (!thiz->context) {
370 GST_WARNING_OBJECT (thiz, "No MSDK Context");
374 if (!thiz->input_state) {
375 GST_DEBUG_OBJECT (thiz, "Have no input state yet");
378 info = &thiz->input_state->info;
379 output_info = &output_state->info;
381 GST_OBJECT_LOCK (thiz);
383 if (thiz->use_video_memory) {
384 gst_msdk_set_frame_allocator (thiz->context);
385 thiz->param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
387 thiz->param.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
390 GST_INFO_OBJECT (thiz, "This MSDK decoder uses %s memory",
391 thiz->use_video_memory ? "video" : "system");
393 thiz->param.AsyncDepth = thiz->async_depth;
395 /* We expect msdk to fill the width and height values */
396 g_return_val_if_fail (thiz->param.mfx.FrameInfo.Width
397 && thiz->param.mfx.FrameInfo.Height, FALSE);
399 klass->preinit_decoder (thiz);
401 /* Set frame rate only if provided.
402 * If not, frame rate will be assumed inside the driver.
403 * Also we respect the upstream provided fps values */
404 if (info->fps_n > 0 && info->fps_d > 0
405 && info->fps_n != thiz->param.mfx.FrameInfo.FrameRateExtN
406 && info->fps_d != thiz->param.mfx.FrameInfo.FrameRateExtD) {
407 thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
408 thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
411 if (info->par_n && info->par_d && !thiz->param.mfx.FrameInfo.AspectRatioW
412 && !thiz->param.mfx.FrameInfo.AspectRatioH) {
413 thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
414 thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
417 thiz->param.mfx.FrameInfo.FourCC =
418 thiz->param.mfx.FrameInfo.FourCC ? thiz->param.mfx.
419 FrameInfo.FourCC : MFX_FOURCC_NV12;
420 thiz->param.mfx.FrameInfo.ChromaFormat =
421 thiz->param.mfx.FrameInfo.ChromaFormat ? thiz->param.mfx.
422 FrameInfo.ChromaFormat : MFX_CHROMAFORMAT_YUV420;
424 #if (MFX_VERSION >= 1022)
425 if (output_info && thiz->sfc) {
426 memset (&ext_dec_video_proc, 0, sizeof (ext_dec_video_proc));
427 ext_dec_video_proc.Header.BufferId = MFX_EXTBUFF_DEC_VIDEO_PROCESSING;
428 ext_dec_video_proc.Header.BufferSz = sizeof (ext_dec_video_proc);
429 ext_dec_video_proc.In.CropW = thiz->param.mfx.FrameInfo.CropW;
430 ext_dec_video_proc.In.CropH = thiz->param.mfx.FrameInfo.CropH;
431 ext_dec_video_proc.In.CropX = 0;
432 ext_dec_video_proc.In.CropY = 0;
433 ext_dec_video_proc.Out.FourCC =
434 gst_msdk_get_mfx_fourcc_from_format (output_info->finfo->format);
435 ext_dec_video_proc.Out.ChromaFormat =
436 gst_msdk_get_mfx_chroma_from_format (output_info->finfo->format);
437 ext_dec_video_proc.Out.Width = GST_ROUND_UP_16 (output_info->width);
438 ext_dec_video_proc.Out.Height = GST_ROUND_UP_32 (output_info->height);
439 ext_dec_video_proc.Out.CropW = output_info->width;
440 ext_dec_video_proc.Out.CropH = output_info->height;
441 ext_dec_video_proc.Out.CropX = 0;
442 ext_dec_video_proc.Out.CropY = 0;
443 gst_msdkdec_add_video_extra_param (thiz,
444 (mfxExtBuffer *) & ext_dec_video_proc);
448 if (thiz->num_video_extra_params) {
449 thiz->param.NumExtParam = thiz->num_video_extra_params;
450 thiz->param.ExtParam = thiz->video_extra_params;
453 session = gst_msdk_context_get_session (thiz->context);
454 /* validate parameters and allow MFX to make adjustments */
455 status = MFXVideoDECODE_Query (session, &thiz->param, &thiz->param);
456 if (status < MFX_ERR_NONE) {
457 GST_ERROR_OBJECT (thiz, "Video Decode Query failed (%s)",
458 msdk_status_to_string (status));
460 } else if (status > MFX_ERR_NONE) {
461 GST_WARNING_OBJECT (thiz, "Video Decode Query returned: %s",
462 msdk_status_to_string (status));
465 klass->postinit_decoder (thiz);
467 status = MFXVideoDECODE_QueryIOSurf (session, &thiz->param, &request);
468 if (status < MFX_ERR_NONE) {
469 GST_ERROR_OBJECT (thiz, "Query IO surfaces failed (%s)",
470 msdk_status_to_string (status));
472 } else if (status > MFX_ERR_NONE) {
473 GST_WARNING_OBJECT (thiz, "Query IO surfaces returned: %s",
474 msdk_status_to_string (status));
477 if (request.NumFrameSuggested < thiz->param.AsyncDepth) {
478 GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
479 request.NumFrameMin, request.NumFrameSuggested, thiz->param.AsyncDepth);
483 /* account for downstream requirement */
484 if (G_LIKELY (thiz->min_prealloc_buffers))
485 request.NumFrameSuggested += thiz->min_prealloc_buffers;
487 GST_WARNING_OBJECT (thiz,
488 "Allocating resources without considering the downstream requirement"
489 "or extra scratch surface count");
491 if (thiz->use_video_memory) {
492 gint shared_async_depth;
495 gst_msdk_context_get_shared_async_depth (thiz->context);
496 request.NumFrameSuggested += shared_async_depth;
498 request.Type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
499 if (thiz->use_dmabuf)
500 request.Type |= MFX_MEMTYPE_EXPORT_FRAME;
501 #if (MFX_VERSION >= 1022)
503 request.Info.Width = ext_dec_video_proc.Out.Width;
504 request.Info.Height = ext_dec_video_proc.Out.Height;
508 gst_msdk_frame_alloc (thiz->context, &request, &thiz->alloc_resp);
511 /* update the prealloc_buffer count, which will be used later
512 * as GstBufferPool min_buffers */
513 thiz->min_prealloc_buffers = request.NumFrameSuggested;
515 GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested)",
516 request.NumFrameMin, request.NumFrameSuggested);
518 status = MFXVideoDECODE_Init (session, &thiz->param);
519 if (status < MFX_ERR_NONE) {
520 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
522 } else if (status > MFX_ERR_NONE) {
523 GST_WARNING_OBJECT (thiz, "Init returned: %s",
524 msdk_status_to_string (status));
527 status = MFXVideoDECODE_GetVideoParam (session, &thiz->param);
528 if (status < MFX_ERR_NONE) {
529 GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
530 msdk_status_to_string (status));
532 } else if (status > MFX_ERR_NONE) {
533 GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
534 msdk_status_to_string (status));
537 g_array_set_size (thiz->tasks, 0); /* resets array content */
538 g_array_set_size (thiz->tasks, thiz->param.AsyncDepth);
541 GST_OBJECT_UNLOCK (thiz);
543 thiz->initialized = TRUE;
547 GST_OBJECT_UNLOCK (thiz);
553 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
557 for (i = 0; i < gst_caps_get_size (caps); i++) {
558 GstCapsFeatures *const features = gst_caps_get_features (caps, i);
559 /* Skip ANY features, we need an exact match for correct evaluation */
560 if (gst_caps_features_is_any (features))
562 if (gst_caps_features_contains (features, feature))
570 srcpad_can_dmabuf (GstMsdkDec * thiz)
572 gboolean ret = FALSE;
573 GstCaps *caps, *out_caps;
576 srcpad = GST_VIDEO_DECODER_SRC_PAD (thiz);
577 caps = gst_pad_get_pad_template_caps (srcpad);
579 out_caps = gst_pad_peer_query_caps (srcpad, caps);
583 if (gst_caps_is_any (out_caps) || gst_caps_is_empty (out_caps)
587 if (_gst_caps_has_feature (out_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
592 gst_caps_unref (caps);
594 gst_caps_unref (out_caps);
599 gst_msdkdec_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
601 GstCaps *caps, *tmp = NULL;
603 caps = gst_pad_get_pad_template_caps (decoder->sinkpad);
606 tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
607 gst_caps_unref (caps);
611 caps = gst_video_decoder_proxy_getcaps (decoder, NULL, filter);
618 gst_msdkdec_set_src_caps (GstMsdkDec * thiz, gboolean need_allocation)
620 GstVideoCodecState *output_state;
622 GstVideoAlignment align;
623 GstCaps *allocation_caps = NULL;
624 GstCaps *allowed_caps = NULL, *temp_caps;
625 GstVideoFormat format;
627 guint alloc_w, alloc_h;
628 int out_width = 0, out_height = 0;
629 gint dar_n = -1, dar_d = -1;
630 const gchar *format_str;
631 GstStructure *outs = NULL;
632 const gchar *out_format;
633 GValue v_format = G_VALUE_INIT;
634 GValue v_width = G_VALUE_INIT;
635 GValue v_height = G_VALUE_INIT;
637 /* use display width and display height in output state, which
638 * will be used for caps negotiation */
640 thiz->param.mfx.FrameInfo.CropW ? thiz->param.mfx.
641 FrameInfo.CropW : GST_VIDEO_INFO_WIDTH (&thiz->input_state->info);
643 thiz->param.mfx.FrameInfo.CropH ? thiz->param.mfx.
644 FrameInfo.CropH : GST_VIDEO_INFO_HEIGHT (&thiz->input_state->info);
647 gst_msdk_get_video_format_from_mfx_fourcc (thiz->param.mfx.
650 if (format == GST_VIDEO_FORMAT_UNKNOWN) {
651 GST_WARNING_OBJECT (thiz, "Failed to find a valid video format");
654 #if (MFX_VERSION >= 1022)
655 /* SFC is triggered (for AVC and HEVC) when default output format is not
656 * accepted by downstream or when downstream requests for a smaller
657 * resolution (i.e. SFC supports down-scaling)
658 * Here we need to do the query twice: the first time uses default color
659 * format and bitstream's original size to query peer pad, empty caps
660 * means default format and/or size are not accepted by downstream;
661 * then we need the second query to decide src caps' color format and size,
662 * and let SFC work. */
663 if (thiz->param.mfx.CodecId == MFX_CODEC_AVC ||
664 thiz->param.mfx.CodecId == MFX_CODEC_HEVC) {
665 temp_caps = gst_pad_query_caps (GST_VIDEO_DECODER (thiz)->srcpad, NULL);
666 temp_caps = gst_caps_make_writable (temp_caps);
668 g_value_init (&v_format, G_TYPE_STRING);
669 g_value_init (&v_width, G_TYPE_INT);
670 g_value_init (&v_height, G_TYPE_INT);
672 g_value_set_string (&v_format, gst_video_format_to_string (format));
673 g_value_set_int (&v_width, width);
674 g_value_set_int (&v_height, height);
676 gst_caps_set_value (temp_caps, "format", &v_format);
677 gst_caps_set_value (temp_caps, "width", &v_width);
678 gst_caps_set_value (temp_caps, "height", &v_height);
680 if (gst_caps_is_empty (gst_pad_peer_query_caps (GST_VIDEO_DECODER
681 (thiz)->srcpad, temp_caps))) {
682 if (!gst_util_fraction_multiply (width, height,
683 GST_VIDEO_INFO_PAR_N (&thiz->input_state->info),
684 GST_VIDEO_INFO_PAR_D (&thiz->input_state->info),
686 GST_ERROR_OBJECT (thiz, "Error to calculate the output scaled size");
687 gst_caps_unref (temp_caps);
692 gst_pad_get_allowed_caps (GST_VIDEO_DECODER (thiz)->srcpad);
693 outs = gst_caps_get_structure (allowed_caps, 0);
694 out_format = gst_structure_get_string (outs, "format");
695 gst_structure_get_int (outs, "width", &out_width);
696 gst_structure_get_int (outs, "height", &out_height);
699 format = gst_video_format_from_string (out_format);
703 if (!out_width && !out_height) {
707 /* When user does not set out_width, fill it to fit DAR */
709 out_width = gst_util_uint64_scale (out_height, dar_n, dar_d);
710 /* When user does not set out_height, fill it to fit DAR */
712 out_height = gst_util_uint64_scale (out_width, dar_d, dar_n);
714 if (out_width > width || out_height > height)
716 else if (out_width < width || out_height < height) {
722 gst_caps_unref (allowed_caps);
724 gst_caps_unref (temp_caps);
729 gst_video_decoder_set_output_state (GST_VIDEO_DECODER (thiz),
730 format, width, height, thiz->input_state);
734 /* Find allocation width and height */
736 GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
737 FrameInfo.Width : width);
739 GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
740 FrameInfo.Height : height);
742 /* Ensure output_state->caps and info have same width and height
743 * Also, mandate 32 bit alignment */
744 vinfo = &output_state->info;
745 if (width == out_width || height == out_height)
746 gst_msdk_set_video_alignment (vinfo, 0, 0, &align);
748 gst_msdk_set_video_alignment (vinfo, alloc_w, alloc_h, &align);
749 gst_video_info_align (vinfo, &align);
750 output_state->caps = gst_video_info_to_caps (vinfo);
752 if (srcpad_can_dmabuf (thiz))
753 gst_caps_set_features (output_state->caps, 0,
754 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
756 if (need_allocation) {
757 /* Find allocation width and height */
759 GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
760 FrameInfo.Width : GST_VIDEO_INFO_WIDTH (&output_state->info));
762 GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
763 FrameInfo.Height : GST_VIDEO_INFO_HEIGHT (&output_state->info));
765 /* set allocation width and height in allocation_caps,
766 * which may or may not be similar to the output_state caps */
767 allocation_caps = gst_caps_copy (output_state->caps);
769 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
770 (&output_state->info));
771 gst_caps_set_simple (allocation_caps, "width", G_TYPE_INT, width, "height",
772 G_TYPE_INT, height, "format", G_TYPE_STRING, format_str, NULL);
773 GST_INFO_OBJECT (thiz, "new alloc caps = %" GST_PTR_FORMAT,
775 gst_caps_replace (&output_state->allocation_caps, allocation_caps);
776 gst_caps_unref (allocation_caps);
778 /* We keep the allocation parameters as it is to avoid pool re-negotiation.
779 * For codecs like VP9, dynamic resolution change doesn't require allocation
780 * reset if the new video frame resolution is lower than the
781 * already configured one */
783 gst_video_codec_state_unref (output_state);
788 GST_ERROR_OBJECT (thiz, "Decoder SFC cannot do up-scaling");
789 gst_caps_unref (allowed_caps);
790 gst_caps_unref (temp_caps);
795 gst_msdkdec_set_latency (GstMsdkDec * thiz)
797 GstVideoInfo *info = &thiz->input_state->info;
798 gint min_delayed_frames;
799 GstClockTime latency;
801 min_delayed_frames = thiz->async_depth;
804 latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
805 min_delayed_frames, info->fps_n);
807 /* FIXME: Assume 25fps. This is better than reporting no latency at
808 * all and then later failing in live pipelines
810 latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
811 min_delayed_frames, 25);
814 GST_INFO_OBJECT (thiz,
815 "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
816 GST_TIME_ARGS (latency), min_delayed_frames);
818 gst_video_decoder_set_latency (GST_VIDEO_DECODER (thiz), latency, latency);
822 _find_msdk_surface (gconstpointer msdk_surface, gconstpointer comp_surface)
824 MsdkSurface *cached_surface = (MsdkSurface *) msdk_surface;
825 mfxFrameSurface1 *_surface = (mfxFrameSurface1 *) comp_surface;
827 return cached_surface ? cached_surface->surface != _surface : -1;
831 finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
833 MsdkSurface *surface = task->surface;
835 if (G_UNLIKELY (surface->copy.buffer)) {
836 unmap_frame (thiz, surface);
838 thiz->locked_msdk_surfaces =
839 g_list_append (thiz->locked_msdk_surfaces, surface);
841 task->sync_point = NULL;
842 task->surface = NULL;
843 task->decode_only = FALSE;
847 gst_msdkdec_frame_corruption_report (GstMsdkDec * thiz, mfxU16 corruption)
849 if (!thiz->report_error || !corruption)
852 if (corruption & MFX_CORRUPTION_MINOR)
853 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
854 ("[Corruption] Minor corruption detected!"), (NULL));
856 if (corruption & MFX_CORRUPTION_MAJOR)
857 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
858 ("[Corruption] Major corruption detected!"), (NULL));
860 if (corruption & MFX_CORRUPTION_ABSENT_TOP_FIELD)
861 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
862 ("[Corruption] Absent top field!"), (NULL));
864 if (corruption & MFX_CORRUPTION_ABSENT_BOTTOM_FIELD)
865 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
866 ("[Corruption] Absent bottom field!"), (NULL));
868 if (corruption & MFX_CORRUPTION_REFERENCE_FRAME)
869 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
870 ("[Corruption] Corrupted reference frame!"), (NULL));
872 if (corruption & MFX_CORRUPTION_REFERENCE_LIST)
873 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
874 ("[Corruption] Corrupted reference list!"), (NULL));
878 gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
880 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
882 GstVideoCodecFrame *frame;
883 MsdkSurface *surface;
885 guint64 pts = MFX_TIMESTAMP_UNKNOWN;
887 if (G_LIKELY (task->sync_point)) {
889 MFXVideoCORE_SyncOperation (gst_msdk_context_get_session
890 (thiz->context), task->sync_point, 300000);
891 if (status != MFX_ERR_NONE) {
892 GST_ERROR_OBJECT (thiz, "failed to do sync operation");
893 return GST_FLOW_ERROR;
897 surface = task->surface;
899 gst_msdkdec_frame_corruption_report (thiz,
900 surface->surface->Data.Corrupted);
901 GST_DEBUG_OBJECT (thiz, "Decoded MFX TimeStamp: %" G_GUINT64_FORMAT,
902 (guint64) surface->surface->Data.TimeStamp);
903 pts = surface->surface->Data.TimeStamp;
906 if (G_LIKELY (task->sync_point || (surface && task->decode_only))) {
907 gboolean decode_only = task->decode_only;
909 frame = gst_msdkdec_get_oldest_frame (decoder);
910 /* align decoder frame list with current decoded position */
911 while (frame && MFX_TIME_IS_VALID (pts)
912 && GST_CLOCK_TIME_IS_VALID (frame->pts)
913 && GST_TO_MFX_TIME (frame->pts) < pts) {
914 GST_INFO_OBJECT (thiz, "Discarding frame: %p PTS: %" GST_TIME_FORMAT
915 " MFX TimeStamp: %" G_GUINT64_FORMAT,
916 frame, GST_TIME_ARGS (frame->pts), GST_TO_MFX_TIME (frame->pts));
917 gst_video_decoder_release_frame (decoder, frame);
918 frame = gst_msdkdec_get_oldest_frame (decoder);
921 if (G_LIKELY (frame)) {
922 if (G_LIKELY (surface->copy.buffer == NULL)) {
923 /* gst_video_decoder_finish_frame will call gst_buffer_make_writable
924 * we need this to avoid copy buffer */
925 GST_MINI_OBJECT_FLAG_SET (surface->buf, GST_MINI_OBJECT_FLAG_LOCKABLE);
926 frame->output_buffer = gst_buffer_ref (surface->buf);
928 if (!gst_video_frame_copy (&surface->copy, &surface->data)) {
929 GST_ERROR_OBJECT (thiz, "Failed to copy surface data");
930 gst_video_frame_unmap (&surface->copy);
931 gst_video_frame_unmap (&surface->data);
932 return GST_FLOW_ERROR;
934 frame->output_buffer = gst_buffer_ref (surface->copy.buffer);
935 unmap_frame (thiz, surface);
937 GST_DEBUG_OBJECT (thiz, "surface %p TimeStamp: %" G_GUINT64_FORMAT
938 " frame %p TimeStamp: %" G_GUINT64_FORMAT,
939 surface->surface, (guint64) surface->surface->Data.TimeStamp,
940 frame, GST_TO_MFX_TIME (frame->pts));
943 finish_task (thiz, task);
946 return GST_FLOW_FLUSHING;
949 GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
951 frame->pts = MFX_TO_GST_TIME (pts);
952 flow = gst_video_decoder_finish_frame (decoder, frame);
953 if (flow == GST_FLOW_ERROR)
954 GST_ERROR_OBJECT (thiz, "Failed to finish frame");
957 finish_task (thiz, task);
962 gst_msdkdec_context_prepare (GstMsdkDec * thiz)
964 /* Try to find an existing context from the pipeline. This may (indirectly)
965 * invoke gst_msdkdec_set_context, which will set thiz->context. */
966 if (!gst_msdk_context_find (GST_ELEMENT_CAST (thiz), &thiz->context))
969 if (thiz->context == thiz->old_context) {
970 GST_INFO_OBJECT (thiz, "Found old context %" GST_PTR_FORMAT
971 ", reusing as-is", thiz->context);
975 /* TODO: Currently d3d allocator is not implemented.
976 * So decoder uses system memory by default on Windows.
979 thiz->use_video_memory = TRUE;
981 thiz->use_video_memory = FALSE;
984 GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
987 if (!(gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_DECODER)) {
988 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_DECODER);
992 /* Found an existing context that's already being used as a decoder, clone
993 * the MFX session inside it to create a new one */
995 GstMsdkContext *parent_context, *msdk_context;
997 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT " with "
998 "joined session", thiz->context);
999 parent_context = thiz->context;
1000 msdk_context = gst_msdk_context_new_with_parent (parent_context);
1002 if (!msdk_context) {
1003 GST_ERROR_OBJECT (thiz, "Failed to create a context with parent context "
1004 "as %" GST_PTR_FORMAT, parent_context);
1008 thiz->context = msdk_context;
1009 gst_msdk_context_add_shared_async_depth (thiz->context,
1010 gst_msdk_context_get_shared_async_depth (parent_context));
1011 gst_object_unref (parent_context);
1018 gst_msdkdec_start (GstVideoDecoder * decoder)
1020 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1022 if (!gst_msdkdec_context_prepare (thiz)) {
1023 if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
1024 thiz->hardware, GST_MSDK_JOB_DECODER, &thiz->context))
1026 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
1030 /* Save the current context in a separate field so that we know whether it
1031 * has changed between calls to _start() */
1032 gst_object_replace ((GstObject **) & thiz->old_context,
1033 (GstObject *) thiz->context);
1035 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
1041 gst_msdkdec_close (GstVideoDecoder * decoder)
1043 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1045 gst_clear_object (&thiz->context);
1051 gst_msdkdec_stop (GstVideoDecoder * decoder)
1053 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1055 gst_msdkdec_flush (decoder);
1057 if (thiz->input_state) {
1058 gst_video_codec_state_unref (thiz->input_state);
1059 thiz->input_state = NULL;
1062 gst_object_unref (thiz->pool);
1065 gst_video_info_init (&thiz->non_msdk_pool_info);
1067 gst_msdkdec_close_decoder (thiz, TRUE);
1072 gst_msdkdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
1074 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1076 if (thiz->input_state) {
1077 /* mark for re-negotiation if display resolution or any other video info
1078 * changes like framerate. */
1079 if (!gst_video_info_is_equal (&thiz->input_state->info, &state->info)) {
1080 GST_INFO_OBJECT (thiz, "Schedule renegotiation as video info changed");
1081 thiz->do_renego = TRUE;
1083 gst_video_codec_state_unref (thiz->input_state);
1085 thiz->input_state = gst_video_codec_state_ref (state);
1087 /* we don't set output state here to avoid caching of mismatched
1088 * video information if there is dynamic resolution change in the stream.
1089 * All negotiation code is consolidated in gst_msdkdec_negotiate() and
1090 * this will be invoked from handle_frame() */
1092 gst_msdkdec_set_latency (thiz);
1097 release_msdk_surfaces (GstMsdkDec * thiz)
1100 MsdkSurface *surface;
1102 gst_msdkdec_free_unlocked_msdk_surfaces (thiz);
1104 for (l = thiz->locked_msdk_surfaces; l; l = l->next) {
1105 surface = (MsdkSurface *) l->data;
1106 unmap_frame (thiz, surface);
1107 free_surface (surface);
1111 GST_ERROR_OBJECT (thiz, "msdk still locked %d surfaces", locked);
1112 g_list_free (thiz->locked_msdk_surfaces);
1113 thiz->locked_msdk_surfaces = NULL;
1116 /* This will get invoked in the following situations:
1117 * 1: beginning of the stream, which requires initialization (== complete reset)
1118 * 2: upstream notified a resolution change and set do_renego to TRUE.
1119 * new resolution may or may not requires full reset
1120 * 3: upstream failed to notify the resolution change but
1121 * msdk detected the change (eg: vp9 stream in ivf elementary form
1122 * with varying resolution frames).
1124 * for any input configuration change, we deal with notification
1125 * from upstream and also use msdk APIs to handle the parameter initialization
1129 gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset)
1131 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
1132 GST_DEBUG_OBJECT (thiz,
1133 "Start Negotiating caps, pool and Init the msdk decdoer subsystem");
1136 /* Retrieve any pending frames and push them downstream */
1137 if (gst_msdkdec_drain (GST_VIDEO_DECODER (thiz)) != GST_FLOW_OK)
1140 /* This will initiate the allocation query which will help to flush
1141 * all the pending buffers in the pipeline so that we can stop
1142 * the active bufferpool and safely invoke gst_msdk_frame_free() */
1143 if (thiz->initialized) {
1144 GstCaps *caps = gst_pad_get_current_caps (decoder->srcpad);
1145 GstQuery *query = NULL;
1147 query = gst_query_new_allocation (caps, FALSE);
1148 gst_pad_peer_query (decoder->srcpad, query);
1149 gst_query_unref (query);
1150 gst_caps_unref (caps);
1154 /* De-initialize the decoder if it is already active */
1155 /* Do not reset the mfxVideoParam since it already
1156 * has the required parameters for new session decode */
1157 gst_msdkdec_close_decoder (thiz, FALSE);
1159 /* request for pool re-negotiation by setting do_realloc */
1160 thiz->do_realloc = TRUE;
1163 /* At this point all pending frames (if there are any) are pushed downstream
1164 * and we are ready to negotiate the output caps */
1165 if (!gst_msdkdec_set_src_caps (thiz, hard_reset))
1168 /* this will initiate the allocation query, we create the
1169 * bufferpool in decide_allocation in order to account
1170 * for the downstream min_buffer requirement
1171 * Required initializations for MediaSDK operations
1172 * will all be initialized from decide_allocation after considering
1173 * some of the downstream requirements */
1174 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (thiz)))
1175 goto error_negotiate;
1177 thiz->do_renego = FALSE;
1178 thiz->do_realloc = FALSE;
1183 GST_ERROR_OBJECT (thiz, "Failed to Drain the queued decoded frames");
1187 GST_ERROR_OBJECT (thiz, "Failed to re-negotiate");
1191 static inline gboolean
1192 find_msdk_surface (GstMsdkDec * thiz, MsdkDecTask * task,
1193 mfxFrameSurface1 * out_surface)
1196 task->surface = NULL;
1200 l = g_list_find_custom (thiz->locked_msdk_surfaces, out_surface,
1201 _find_msdk_surface);
1203 GST_ERROR_OBJECT (thiz, "msdk return an invalid surface %p", out_surface);
1206 task->surface = (MsdkSurface *) l->data;
1207 thiz->locked_msdk_surfaces =
1208 g_list_delete_link (thiz->locked_msdk_surfaces, l);
1213 gst_msdkdec_error_report (GstMsdkDec * thiz)
1215 if (!thiz->report_error)
1218 #if (MFX_VERSION >= 1025)
1220 if (thiz->error_report.ErrorTypes & MFX_ERROR_SPS)
1221 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1222 ("[Error] SPS Error detected!"), (NULL));
1224 if (thiz->error_report.ErrorTypes & MFX_ERROR_PPS)
1225 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1226 ("[Error] PPS Error detected!"), (NULL));
1228 if (thiz->error_report.ErrorTypes & MFX_ERROR_SLICEHEADER)
1229 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1230 ("[Error] SliceHeader Error detected!"), (NULL));
1232 if (thiz->error_report.ErrorTypes & MFX_ERROR_FRAME_GAP)
1233 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1234 ("[Error] Frame Gap Error detected!"), (NULL));
1236 #ifdef ONEVPL_EXPERIMENTAL
1237 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_APP0_MARKER)
1238 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1239 ("[Error] APP0 unknown marker detected!"), (NULL));
1241 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_APP14_MARKER)
1242 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1243 ("[Error] APP14 unknown marker detected!"), (NULL));
1245 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_DQT_MARKER)
1246 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1247 ("[Error] DQT unknown marker detected!"), (NULL));
1249 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_SOF0_MARKER)
1250 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1251 ("[Error] SOF0 unknown marker detected!"), (NULL));
1253 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_DHT_MARKER)
1254 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1255 ("[Error] DHT unknown marker detected!"), (NULL));
1257 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_DRI_MARKER)
1258 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1259 ("[Error] DRI unknown marker detected!"), (NULL));
1261 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_SOS_MARKER)
1262 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1263 ("[Error] SOS unknown marker detected!"), (NULL));
1265 if (thiz->error_report.ErrorTypes & MFX_ERROR_JPEG_UNKNOWN_MARKER)
1266 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1267 ("[Error] Error unknown marker detected!"), (NULL));
1273 static GstFlowReturn
1274 gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
1276 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1277 GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
1279 GstBuffer *buffer, *input_buffer = NULL;
1280 GstVideoInfo alloc_info;
1281 MsdkDecTask *task = NULL;
1282 mfxBitstream bitstream;
1283 MsdkSurface *surface = NULL;
1284 mfxFrameSurface1 *out_surface = NULL;
1287 GstMapInfo map_info;
1288 guint i, retry_err_incompatible = 0;
1290 gboolean hard_reset = FALSE;
1291 GstClockTime pts = GST_CLOCK_TIME_NONE;
1293 /* configure the subclass in order to fill the CodecID field of
1294 * mfxVideoParam and also to load the PluginID for some of the
1295 * codecs which is mandatory to invoke the
1296 * MFXVideoDECODE_DecodeHeader API.
1298 * For non packetized formats (currently only vc1), there
1299 * could be headers received as codec_data which are not available
1300 * instream and in that case subclass implementation will
1301 * push it to the internal adapter. We invoke the subclass configure
1302 * well early to make sure the codec_data received has been correctly
1303 * pushed to the adapter by the subclasses before doing
1304 * the DecodeHeader() later on
1306 if (!thiz->initialized || thiz->do_renego) {
1307 /* Clear the internal adapter in re-negotiation for non-packetized
1309 if (!gst_video_decoder_get_packetized (decoder))
1310 gst_adapter_clear (thiz->adapter);
1312 if (!klass->configure || !klass->configure (thiz)) {
1318 /* Current frame-codec could be pushed and released before this
1319 * function ends -- because msdkdec pushes the oldest frame,
1320 * according its PTS, and it could be this very same frame-codec
1321 * among others pending frame-codecs.
1323 * Instead of copying the input data into the mfxBitstream, let's
1324 * keep an extra reference to frame-codec's input buffer */
1325 input_buffer = gst_buffer_ref (frame->input_buffer);
1326 if (!gst_buffer_map (input_buffer, &map_info, GST_MAP_READ)) {
1327 gst_buffer_unref (input_buffer);
1328 return GST_FLOW_ERROR;
1331 memset (&bitstream, 0, sizeof (bitstream));
1333 /* Add extended buffers */
1334 if (thiz->num_bs_extra_params) {
1335 bitstream.NumExtParam = thiz->num_bs_extra_params;
1336 bitstream.ExtParam = thiz->bs_extra_params;
1339 if (gst_video_decoder_get_packetized (decoder)) {
1340 /* Packetized stream: we prefer to have a parser as a connected upstream
1341 * element to the decoder */
1343 bitstream.Data = map_info.data;
1344 bitstream.DataLength = map_info.size;
1345 bitstream.MaxLength = map_info.size;
1346 bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
1349 * MFX_BITSTREAM_COMPLETE_FRAME was removed since commit df59db9, however
1350 * some customers still use DecodedOrder (deprecated in msdk-2017 version)
1351 * for low-latency streaming of non-b-frame encoded streams, which needs to
1352 * output the frame at once, so add it back for this case
1354 if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
1355 bitstream.DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME;
1357 /* Non packetized streams: eg: vc1 advanced profile with per buffer bdu */
1358 gst_adapter_push (thiz->adapter, gst_buffer_ref (input_buffer));
1359 data_size = gst_adapter_available (thiz->adapter);
1361 bitstream.Data = (mfxU8 *) gst_adapter_map (thiz->adapter, data_size);
1362 bitstream.DataLength = (mfxU32) data_size;
1363 bitstream.MaxLength = bitstream.DataLength;
1364 bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
1366 GST_DEBUG_OBJECT (thiz,
1367 "mfxBitStream=> DataLength:%d DataOffset:%d MaxLength:%d "
1368 "PTS: %" GST_TIME_FORMAT " MFX TimeStamp %" G_GUINT64_FORMAT,
1369 bitstream.DataLength, bitstream.DataOffset, bitstream.MaxLength,
1370 GST_TIME_ARGS (pts), (guint64) bitstream.TimeStamp);
1372 session = gst_msdk_context_get_session (thiz->context);
1374 if (!thiz->initialized || thiz->do_renego) {
1376 /* gstreamer caps will not provide all the necessary parameters
1377 * required for optimal decode configuration. For example: the required number
1378 * of surfaces to be allocated can be calculated based on H264 SEI header
1379 * and this information can't be retrieved from the negotiated caps.
1380 * So instead of introducing a codecparser dependency to parse the headers
1381 * inside msdk plugin, we simply use the mfx APIs to extract header information */
1382 #if (MFX_VERSION >= 1025)
1383 if (thiz->report_error)
1384 thiz->error_report.ErrorTypes = 0;
1387 status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1388 GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1389 gst_msdkdec_error_report (thiz);
1391 if (status == MFX_ERR_MORE_DATA) {
1396 if (!klass->post_configure (thiz)) {
1397 flow = GST_FLOW_ERROR;
1401 if (!thiz->initialized)
1404 GstVideoCodecState *output_state =
1405 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1407 if (output_state->allocation_caps) {
1408 if (!gst_video_info_from_caps (&alloc_info,
1409 output_state->allocation_caps)) {
1410 GST_ERROR_OBJECT (thiz, "Failed to get video info from caps");
1411 flow = GST_FLOW_ERROR;
1415 /* Check whether we need complete reset for dynamic resolution change */
1416 if (thiz->param.mfx.FrameInfo.Width >
1417 GST_VIDEO_INFO_WIDTH (&alloc_info)
1418 || thiz->param.mfx.FrameInfo.Height >
1419 GST_VIDEO_INFO_HEIGHT (&alloc_info))
1422 gst_video_codec_state_unref (output_state);
1427 /* if subclass requested for the force reset */
1428 if (thiz->force_reset_on_res_change)
1431 if (!gst_msdkdec_negotiate (thiz, hard_reset)) {
1432 GST_ELEMENT_ERROR (thiz, CORE, NEGOTIATION,
1433 ("Could not negotiate the stream"), (NULL));
1434 flow = GST_FLOW_ERROR;
1439 /* gst_msdkdec_handle_frame owns one ref on input argument |frame|. At this
1440 * point this frame is not used so just unref it right away.
1441 * gst_msdkdec_finish_task is fetching the frames itself. */
1442 gst_video_codec_frame_unref (frame);
1445 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1446 flow = gst_msdkdec_finish_task (thiz, task);
1447 if (flow != GST_FLOW_OK) {
1448 if (flow == GST_FLOW_ERROR)
1449 GST_ERROR_OBJECT (thiz, "Failed to finish a task");
1453 flow = allocate_output_buffer (thiz, &buffer);
1454 if (flow == GST_FLOW_CUSTOM_SUCCESS) {
1457 } else if (flow != GST_FLOW_OK)
1459 surface = get_surface (thiz, buffer);
1461 /* Can't get a surface for some reason; finish tasks, then see if
1462 a surface becomes available. */
1463 for (i = 0; i < thiz->tasks->len - 1; i++) {
1464 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1465 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1466 flow = gst_msdkdec_finish_task (thiz, task);
1467 if (flow != GST_FLOW_OK)
1469 surface = get_surface (thiz, buffer);
1474 GST_ERROR_OBJECT (thiz, "Couldn't get a surface");
1475 flow = GST_FLOW_ERROR;
1480 #if (MFX_VERSION >= 1025)
1481 if (thiz->report_error)
1482 thiz->error_report.ErrorTypes = 0;
1486 MFXVideoDECODE_DecodeFrameAsync (session, &bitstream, surface->surface,
1487 &out_surface, &task->sync_point);
1489 if (!find_msdk_surface (thiz, task, out_surface)) {
1490 flow = GST_FLOW_ERROR;
1494 GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1495 gst_msdkdec_error_report (thiz);
1497 /* media-sdk requires complete reset since the surface is inadequate
1498 * for further decoding */
1499 if (status == MFX_ERR_INCOMPATIBLE_VIDEO_PARAM &&
1500 retry_err_incompatible++ < 1) {
1501 /* MFX_ERR_INCOMPATIBLE_VIDEO_PARAM means the current mfx surface is not
1502 * suitable for the current frame. Call MFXVideoDECODE_DecodeHeader to get
1503 * the current frame size, then do memory re-allocation, otherwise
1504 * MFXVideoDECODE_DecodeFrameAsync will still fail on next call */
1505 #if (MFX_VERSION >= 1025)
1506 if (thiz->report_error)
1507 thiz->error_report.ErrorTypes = 0;
1509 status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1510 GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1511 gst_msdkdec_error_report (thiz);
1513 if (status == MFX_ERR_MORE_DATA) {
1518 /* Requires memory re-allocation, do a hard reset */
1519 if (!gst_msdkdec_negotiate (thiz, TRUE))
1522 /* The current surface is freed when doing a hard reset; a new surface is
1523 * required for the new resolution */
1528 retry_err_incompatible = 0;
1530 if (G_LIKELY (status == MFX_ERR_NONE)
1531 || (status == MFX_WRN_VIDEO_PARAM_CHANGED)) {
1532 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1534 if (surface->surface->Data.Locked > 0)
1537 if (bitstream.DataLength == 0) {
1540 /* Don't release it if the current surface is in use */
1541 if (surface && task->surface->surface == surface->surface)
1546 } else if (status == MFX_ERR_MORE_DATA) {
1547 if (task->surface) {
1548 task->decode_only = TRUE;
1549 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1552 if (surface->surface->Data.Locked > 0)
1554 flow = GST_VIDEO_DECODER_FLOW_NEED_DATA;
1556 } else if (status == MFX_ERR_MORE_SURFACE) {
1559 } else if (status == MFX_WRN_DEVICE_BUSY) {
1560 /* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
1563 if (surface->surface->Data.Locked > 0)
1566 /* If the current surface is still busy, we should do sync operation,
1567 * then try to decode again
1569 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1570 } else if (status < MFX_ERR_NONE) {
1571 GST_ERROR_OBJECT (thiz, "DecodeFrameAsync failed (%s)",
1572 msdk_status_to_string (status));
1573 flow = GST_FLOW_ERROR;
1578 if (!gst_video_decoder_get_packetized (decoder)) {
1579 /* flush out the data which has already been consumed by msdk */
1580 gst_adapter_flush (thiz->adapter, bitstream.DataOffset);
1584 * DecodedOrder was deprecated in msdk-2017 version, but some
1585 * customers still using this for low-latency streaming of non-b-frame
1586 * encoded streams, which needs to output the frame at once
1588 if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
1589 gst_msdkdec_finish_task (thiz, task);
1592 gst_buffer_unmap (input_buffer, &map_info);
1593 gst_buffer_unref (input_buffer);
1598 gst_buffer_unmap (input_buffer, &map_info);
1599 gst_buffer_unref (input_buffer);
1602 gst_video_decoder_drop_frame (decoder, frame);
1607 static GstFlowReturn
1608 gst_msdkdec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame,
1609 GstAdapter * adapter, gboolean at_eos)
1614 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1616 /* Don't parse the input buffer indeed, it will invoke
1617 * gst_msdkdec_handle_frame to handle the input buffer */
1618 size = gst_adapter_available (adapter);
1619 gst_video_decoder_add_to_frame (decoder, size);
1620 ret = gst_video_decoder_have_frame (decoder);
1621 size = gst_adapter_available (thiz->adapter);
1624 /* The base class will set up a new frame for parsing as
1625 * soon as there is valid data in the buffer */
1626 buffer = gst_adapter_get_buffer (thiz->adapter, size);
1627 gst_adapter_flush (thiz->adapter, size);
1628 gst_adapter_push (adapter, buffer);
1634 static GstBufferPool *
1635 gst_msdkdec_create_buffer_pool (GstMsdkDec * thiz, GstVideoInfo * info,
1638 GstBufferPool *pool = NULL;
1639 GstStructure *config;
1640 GstAllocator *allocator = NULL;
1641 GstVideoAlignment align;
1642 GstCaps *caps = NULL;
1643 GstAllocationParams params = { 0, 31, 0, 0, };
1644 mfxFrameAllocResponse *alloc_resp = NULL;
1646 g_return_val_if_fail (info, NULL);
1647 g_return_val_if_fail (GST_VIDEO_INFO_WIDTH (info)
1648 && GST_VIDEO_INFO_HEIGHT (info), NULL);
1650 alloc_resp = &thiz->alloc_resp;
1652 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
1656 caps = gst_video_info_to_caps (info);
1658 /* allocators should use the same width/height/stride/height_alignment of
1659 * negotiated output caps, which is what we configure in msdk_allocator */
1660 if (thiz->use_dmabuf)
1661 allocator = gst_msdk_dmabuf_allocator_new (thiz->context, info, alloc_resp);
1662 else if (thiz->use_video_memory)
1663 allocator = gst_msdk_video_allocator_new (thiz->context, info, alloc_resp);
1665 allocator = gst_msdk_system_allocator_new (info);
1668 gst_caps_unref (caps);
1669 goto error_no_allocator;
1672 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1673 /* we need register all bufffers when we create the msdk context, so the buffer pool is not resize able */
1674 gst_buffer_pool_config_set_params (config, caps,
1675 GST_VIDEO_INFO_SIZE (info), num_buffers, num_buffers);
1676 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1677 gst_buffer_pool_config_add_option (config,
1678 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1679 gst_caps_unref (caps);
1681 if (thiz->use_video_memory) {
1682 gst_buffer_pool_config_add_option (config,
1683 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
1684 if (thiz->use_dmabuf)
1685 gst_buffer_pool_config_add_option (config,
1686 GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
1690 gst_buffer_pool_config_set_video_alignment (config, &align);
1691 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
1692 gst_object_unref (allocator);
1694 if (!gst_buffer_pool_set_config (pool, config))
1695 goto error_pool_config;
1701 GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1706 GST_INFO_OBJECT (thiz, "failed to create allocator");
1707 gst_object_unref (pool);
1712 GST_INFO_OBJECT (thiz, "failed to set config");
1713 gst_object_unref (pool);
1714 gst_object_unref (allocator);
1720 gst_msdkdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1722 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1723 GstBufferPool *pool = NULL;
1724 GstStructure *pool_config = NULL;
1725 GstCaps *pool_caps /*, *negotiated_caps */ ;
1726 guint size, min_buffers, max_buffers;
1727 GstAllocator *allocator = NULL;
1729 if (!thiz->param.mfx.FrameInfo.Width || !thiz->param.mfx.FrameInfo.Height)
1732 if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
1736 /* Get the buffer pool config decided on by the base class. The base
1737 class ensures that there will always be at least a 0th pool in
1739 gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
1740 pool_config = gst_buffer_pool_get_config (pool);
1742 /* Get the caps of pool and increase the min and max buffers by async_depth.
1743 * We will always have that number of decode operations in-flight */
1744 gst_buffer_pool_config_get_params (pool_config, &pool_caps, &size,
1745 &min_buffers, &max_buffers);
1746 min_buffers += thiz->async_depth;
1748 max_buffers += thiz->async_depth;
1750 /* increase the min_buffers by 1 for smooth display in render pipeline */
1753 /* this will get updated with msdk requirement */
1754 thiz->min_prealloc_buffers = min_buffers;
1756 if (_gst_caps_has_feature (pool_caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
1757 GST_INFO_OBJECT (decoder, "This MSDK decoder uses DMABuf memory");
1758 thiz->use_video_memory = thiz->use_dmabuf = TRUE;
1759 } else if (thiz->sfc)
1760 thiz->use_video_memory = TRUE;
1762 /* Initialize MSDK decoder before new bufferpool tries to alloc each buffer,
1763 * which requires information about frame allocation.
1764 * No effect if already initialized.
1766 if (!gst_msdkdec_init_decoder (thiz))
1769 /* get the updated min_buffers, which account for the msdk requirement as well */
1770 min_buffers = thiz->min_prealloc_buffers;
1772 /* Decoder always use its own pool. So we create a pool if msdk APIs
1773 * previously requested for allocation (do_realloc = TRUE) */
1774 if (thiz->do_realloc || !thiz->pool) {
1775 GstVideoCodecState *output_state =
1776 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1777 gst_clear_object (&thiz->pool);
1778 GST_INFO_OBJECT (decoder, "create new MSDK bufferpool");
1780 gst_msdkdec_create_buffer_pool (thiz, &output_state->info, min_buffers);
1781 gst_video_codec_state_unref (output_state);
1783 GST_ERROR_OBJECT (decoder, "failed to create new pool");
1784 goto failed_to_create_pool;
1789 if (gst_query_get_n_allocation_params (query) > 0) {
1790 gst_query_parse_nth_allocation_param (query, 0, &allocator, NULL);
1791 if (!(GST_IS_MSDK_VIDEO_ALLOCATOR (allocator) ||
1792 GST_IS_MSDK_DMABUF_ALLOCATOR (allocator) ||
1793 GST_IS_MSDK_SYSTEM_ALLOCATOR (allocator)))
1794 thiz->ds_has_no_msdk_allocator = TRUE;
1797 /* If downstream supports video meta and video alignment,
1798 * or downstream doesn't have msdk_allocator, we can replace
1799 * with our own msdk bufferpool and use it.
1801 if ((gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)
1802 && gst_buffer_pool_has_option
1803 (pool, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT))
1804 || thiz->ds_has_no_msdk_allocator) {
1805 GstStructure *config;
1806 GstAllocator *allocator;
1808 /* Remove downstream's pool */
1809 gst_structure_free (pool_config);
1810 gst_object_unref (pool);
1812 pool = gst_object_ref (thiz->pool);
1814 /* Set the allocator of new msdk bufferpool */
1815 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1817 if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
1818 gst_query_set_nth_allocation_param (query, 0, allocator, NULL);
1819 gst_structure_free (config);
1821 /* Unfortunately, downstream doesn't have videometa or alignment support,
1822 * we keep msdk pool as a side-pool that will be decoded into and
1825 GstVideoCodecState *output_state = NULL;
1827 GST_INFO_OBJECT (decoder, "Keep MSDK bufferpool as a side-pool");
1829 /* Update params to downstream's pool */
1830 gst_buffer_pool_config_set_params (pool_config, pool_caps, size,
1831 min_buffers, max_buffers);
1832 if (!gst_buffer_pool_set_config (pool, pool_config))
1833 goto error_set_config;
1834 if (!gst_video_info_from_caps (&thiz->non_msdk_pool_info, pool_caps)) {
1835 GST_ERROR_OBJECT (thiz, "Failed to get video info from caps");
1839 /* update width and height with actual negotiated values */
1841 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1842 GST_VIDEO_INFO_WIDTH (&thiz->non_msdk_pool_info) =
1843 GST_VIDEO_INFO_WIDTH (&output_state->info);
1844 GST_VIDEO_INFO_HEIGHT (&thiz->non_msdk_pool_info) =
1845 GST_VIDEO_INFO_HEIGHT (&output_state->info);
1846 gst_video_codec_state_unref (output_state);
1849 gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
1853 gst_object_unref (pool);
1858 failed_to_create_pool:
1859 GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1861 gst_object_unref (pool);
1865 GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1867 gst_object_unref (pool);
1871 static GstFlowReturn
1872 gst_msdkdec_drain (GstVideoDecoder * decoder)
1874 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1878 MsdkSurface *surface = NULL;
1879 mfxFrameSurface1 *out_surface;
1884 if (!thiz->initialized)
1886 session = gst_msdk_context_get_session (thiz->context);
1889 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1890 if ((flow = gst_msdkdec_finish_task (thiz, task)) != GST_FLOW_OK) {
1891 if (flow != GST_FLOW_FLUSHING)
1892 GST_WARNING_OBJECT (decoder,
1893 "failed to finish the task %p, but keep draining for the remaining frames",
1898 flow = allocate_output_buffer (thiz, &buffer);
1899 if (flow != GST_FLOW_OK)
1901 surface = get_surface (thiz, buffer);
1903 return GST_FLOW_ERROR;
1905 #if (MFX_VERSION >= 1025)
1906 if (thiz->report_error)
1907 thiz->error_report.ErrorTypes = 0;
1911 MFXVideoDECODE_DecodeFrameAsync (session, NULL, surface->surface,
1912 &out_surface, &task->sync_point);
1914 if (!find_msdk_surface (thiz, task, out_surface)) {
1915 return GST_FLOW_ERROR;
1918 GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1919 gst_msdkdec_error_report (thiz);
1921 if (G_LIKELY (status == MFX_ERR_NONE)) {
1922 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1924 } else if (status == MFX_WRN_VIDEO_PARAM_CHANGED) {
1926 } else if (status == MFX_WRN_DEVICE_BUSY) {
1927 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1930 /* If the current surface is still busy, we should do sync operation,
1931 * then try to decode again
1933 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1934 } else if (status == MFX_ERR_MORE_DATA) {
1936 } else if (status == MFX_ERR_MORE_SURFACE) {
1939 } else if (status < MFX_ERR_NONE)
1940 return GST_FLOW_ERROR;
1943 for (i = 0; i < thiz->tasks->len; i++) {
1944 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1945 gst_msdkdec_finish_task (thiz, task);
1946 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1953 gst_msdkdec_flush (GstVideoDecoder * decoder)
1955 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1958 ret = gst_msdkdec_drain (GST_VIDEO_DECODER_CAST (thiz));
1960 return ret == GST_FLOW_OK;
1963 static GstFlowReturn
1964 gst_msdkdec_finish (GstVideoDecoder * decoder)
1966 return gst_msdkdec_drain (decoder);
1970 gst_msdkdec_query (GstVideoDecoder * decoder, GstQuery * query,
1971 GstPadDirection dir)
1973 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1974 gboolean ret = FALSE;
1976 switch (GST_QUERY_TYPE (query)) {
1977 case GST_QUERY_CONTEXT:{
1978 GstMsdkContext *msdk_context = NULL;
1980 gst_object_replace ((GstObject **) & msdk_context,
1981 (GstObject *) thiz->context);
1982 ret = gst_msdk_handle_context_query (GST_ELEMENT_CAST (decoder),
1983 query, msdk_context);
1984 gst_clear_object (&msdk_context);
1988 if (dir == GST_PAD_SRC) {
1990 GST_VIDEO_DECODER_CLASS (parent_class)->src_query (decoder, query);
1993 GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (decoder, query);
2002 gst_msdkdec_src_query (GstVideoDecoder * decoder, GstQuery * query)
2004 return gst_msdkdec_query (decoder, query, GST_PAD_SRC);
2008 gst_msdkdec_sink_query (GstVideoDecoder * decoder, GstQuery * query)
2010 return gst_msdkdec_query (decoder, query, GST_PAD_SINK);
2014 gst_msdkdec_set_property (GObject * object, guint prop_id, const GValue * value,
2017 GstMsdkDec *thiz = GST_MSDKDEC (object);
2020 GST_OBJECT_LOCK (thiz);
2022 state = GST_STATE (thiz);
2023 if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
2024 !(pspec->flags & GST_PARAM_MUTABLE_PLAYING))
2028 case GST_MSDKDEC_PROP_HARDWARE:
2029 thiz->hardware = g_value_get_boolean (value);
2031 case GST_MSDKDEC_PROP_ASYNC_DEPTH:
2032 thiz->async_depth = g_value_get_uint (value);
2035 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2038 GST_OBJECT_UNLOCK (thiz);
2044 GST_WARNING_OBJECT (thiz, "setting property in wrong state");
2045 GST_OBJECT_UNLOCK (thiz);
2050 gst_msdkdec_get_property (GObject * object, guint prop_id, GValue * value,
2053 GstMsdkDec *thiz = GST_MSDKDEC (object);
2055 GST_OBJECT_LOCK (thiz);
2057 case GST_MSDKDEC_PROP_HARDWARE:
2058 g_value_set_boolean (value, thiz->hardware);
2060 case GST_MSDKDEC_PROP_ASYNC_DEPTH:
2061 g_value_set_uint (value, thiz->async_depth);
2064 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2067 GST_OBJECT_UNLOCK (thiz);
2071 gst_msdkdec_dispose (GObject * object)
2073 GstMsdkDec *thiz = GST_MSDKDEC (object);
2075 g_clear_object (&thiz->adapter);
2076 gst_clear_object (&thiz->context);
2077 gst_clear_object (&thiz->old_context);
2079 G_OBJECT_CLASS (parent_class)->dispose (object);
2083 gst_msdkdec_finalize (GObject * object)
2085 GstMsdkDec *thiz = GST_MSDKDEC (object);
2087 g_array_unref (thiz->tasks);
2090 release_msdk_surfaces (thiz);
2092 G_OBJECT_CLASS (parent_class)->finalize (object);
2096 gst_msdkdec_post_configure (GstMsdkDec * decoder)
2103 gst_msdkdec_preinit_decoder (GstMsdkDec * decoder)
2105 decoder->param.mfx.FrameInfo.Width =
2106 GST_ROUND_UP_16 (decoder->param.mfx.FrameInfo.Width);
2107 decoder->param.mfx.FrameInfo.Height =
2108 GST_ROUND_UP_32 (decoder->param.mfx.FrameInfo.Height);
2110 decoder->param.mfx.FrameInfo.PicStruct =
2111 decoder->param.mfx.FrameInfo.PicStruct ? decoder->param.mfx.
2112 FrameInfo.PicStruct : MFX_PICSTRUCT_PROGRESSIVE;
2118 gst_msdkdec_postinit_decoder (GstMsdkDec * decoder)
2125 gst_msdkdec_transform_meta (GstVideoDecoder * decoder,
2126 GstVideoCodecFrame * frame, GstMeta * meta)
2128 const GstMetaInfo *info = meta->info;
2130 if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (decoder, frame,
2134 if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta"))
2141 gst_msdkdec_class_init (GstMsdkDecClass * klass)
2143 GObjectClass *gobject_class;
2144 GstElementClass *element_class;
2145 GstVideoDecoderClass *decoder_class;
2147 gobject_class = G_OBJECT_CLASS (klass);
2148 element_class = GST_ELEMENT_CLASS (klass);
2149 decoder_class = GST_VIDEO_DECODER_CLASS (klass);
2151 gobject_class->set_property = gst_msdkdec_set_property;
2152 gobject_class->get_property = gst_msdkdec_get_property;
2153 gobject_class->dispose = gst_msdkdec_dispose;
2154 gobject_class->finalize = gst_msdkdec_finalize;
2156 element_class->set_context = gst_msdkdec_set_context;
2158 decoder_class->close = GST_DEBUG_FUNCPTR (gst_msdkdec_close);
2159 decoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkdec_start);
2160 decoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkdec_stop);
2161 decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkdec_set_format);
2162 decoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkdec_finish);
2163 decoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkdec_handle_frame);
2164 decoder_class->parse = GST_DEBUG_FUNCPTR (gst_msdkdec_parse);
2165 decoder_class->decide_allocation =
2166 GST_DEBUG_FUNCPTR (gst_msdkdec_decide_allocation);
2167 decoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_msdkdec_getcaps);
2168 decoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkdec_flush);
2169 decoder_class->drain = GST_DEBUG_FUNCPTR (gst_msdkdec_drain);
2170 decoder_class->transform_meta =
2171 GST_DEBUG_FUNCPTR (gst_msdkdec_transform_meta);
2172 decoder_class->src_query = GST_DEBUG_FUNCPTR (gst_msdkdec_src_query);
2173 decoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_msdkdec_sink_query);
2175 klass->post_configure = GST_DEBUG_FUNCPTR (gst_msdkdec_post_configure);
2176 klass->preinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_preinit_decoder);
2177 klass->postinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_postinit_decoder);
2179 g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_HARDWARE,
2180 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware decoders",
2181 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2183 g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_ASYNC_DEPTH,
2184 g_param_spec_uint ("async-depth", "Async Depth",
2185 "Depth of asynchronous pipeline",
2186 1, 20, PROP_ASYNC_DEPTH_DEFAULT,
2187 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2189 gst_element_class_add_static_pad_template (element_class, &src_factory);
2193 gst_msdkdec_init (GstMsdkDec * thiz)
2195 gst_video_info_init (&thiz->non_msdk_pool_info);
2196 thiz->tasks = g_array_new (FALSE, TRUE, sizeof (MsdkDecTask));
2197 thiz->hardware = PROP_HARDWARE_DEFAULT;
2198 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
2199 thiz->do_renego = TRUE;
2200 thiz->do_realloc = TRUE;
2201 thiz->force_reset_on_res_change = TRUE;
2202 thiz->report_error = FALSE;
2204 thiz->ds_has_no_msdk_allocator = FALSE;
2205 thiz->adapter = gst_adapter_new ();
2206 thiz->input_state = NULL;
2208 thiz->context = NULL;