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_TIME_IS_VALID(time) ((time) != MFX_TIMESTAMP_UNKNOWN)
63 #define gst_msdkdec_parent_class parent_class
64 G_DEFINE_TYPE (GstMsdkDec, gst_msdkdec, GST_TYPE_VIDEO_DECODER);
66 typedef struct _MsdkSurface
68 mfxFrameSurface1 *surface;
74 static gboolean gst_msdkdec_drain (GstVideoDecoder * decoder);
75 static gboolean gst_msdkdec_flush (GstVideoDecoder * decoder);
76 static gboolean gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset);
78 static GstVideoCodecFrame *
79 gst_msdkdec_get_oldest_frame (GstVideoDecoder * decoder)
81 GstVideoCodecFrame *frame = NULL, *old_frame = NULL;
85 frames = gst_video_decoder_get_frames (decoder);
87 for (l = frames; l != NULL; l = l->next) {
88 GstVideoCodecFrame *f = l->data;
90 if (!GST_CLOCK_TIME_IS_VALID (f->pts)) {
92 ("Frame doesn't have a valid pts yet, Use gst_video_decoder_get_oldest_frame()"
93 "with out considering the PTS for selecting the frame to be finished");
94 old_frame = gst_video_decoder_get_oldest_frame (decoder);
98 if (!frame || frame->pts > f->pts)
108 GST_LOG_OBJECT (decoder,
109 "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
110 frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
111 gst_video_codec_frame_ref (frame);
115 gst_video_codec_frame_unref (old_frame);
117 g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
123 free_surface (GstMsdkDec * thiz, MsdkSurface * s)
125 if (s->copy.buffer) {
126 gst_video_frame_unmap (&s->copy);
127 gst_buffer_unref (s->copy.buffer);
131 gst_video_frame_unmap (&s->data);
133 gst_buffer_unref (s->buf);
134 thiz->decoded_msdk_surfaces = g_list_remove (thiz->decoded_msdk_surfaces, s);
136 g_slice_free (MsdkSurface, s);
140 gst_msdkdec_free_unlocked_msdk_surfaces (GstMsdkDec * thiz,
141 MsdkSurface * curr_surface)
144 MsdkSurface *surface;
146 for (l = thiz->decoded_msdk_surfaces; l;) {
150 if (surface != curr_surface && surface->surface->Data.Locked == 0)
151 free_surface (thiz, surface);
156 allocate_output_buffer (GstMsdkDec * thiz, GstBuffer ** buffer)
159 GstVideoCodecFrame *frame;
160 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
162 frame = gst_msdkdec_get_oldest_frame (decoder);
164 if (GST_PAD_IS_FLUSHING (decoder->srcpad))
165 return GST_FLOW_FLUSHING;
167 return GST_FLOW_CUSTOM_SUCCESS;
170 if (!frame->output_buffer) {
171 /* Free un-unsed msdk surfaces firstly, hence the associated mfx
172 * surfaces will be moved from used list to available list */
173 if (thiz->postpone_free_surface || thiz->use_video_memory)
174 gst_msdkdec_free_unlocked_msdk_surfaces (thiz, NULL);
176 flow = gst_video_decoder_allocate_output_frame (decoder, frame);
177 if (flow != GST_FLOW_OK) {
178 gst_video_codec_frame_unref (frame);
183 *buffer = gst_buffer_ref (frame->output_buffer);
184 gst_buffer_replace (&frame->output_buffer, NULL);
185 gst_video_codec_frame_unref (frame);
187 if (thiz->postpone_free_surface)
188 GST_MINI_OBJECT_FLAG_SET (*buffer, GST_MINI_OBJECT_FLAG_LOCKABLE);
194 get_surface (GstMsdkDec * thiz, GstBuffer * buffer)
197 GstVideoCodecState *output_state = NULL;
200 i = g_slice_new0 (MsdkSurface);
202 if (gst_msdk_is_msdk_buffer (buffer)) {
203 i->surface = gst_msdk_get_surface_from_buffer (buffer);
206 /* Confirm to activate the side pool */
207 if (!gst_buffer_pool_is_active (thiz->pool) &&
208 !gst_buffer_pool_set_active (thiz->pool, TRUE)) {
209 g_slice_free (MsdkSurface, i);
213 if (!gst_video_frame_map (&i->copy, &thiz->non_msdk_pool_info, buffer,
215 goto failed_unref_buffer;
217 if (gst_buffer_pool_acquire_buffer (thiz->pool, &buffer,
218 NULL) != GST_FLOW_OK)
219 goto failed_unmap_copy;
221 i->surface = gst_msdk_get_surface_from_buffer (buffer);
225 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
227 gst_video_frame_map (&i->data, &output_state->info, buffer,
229 gst_video_codec_state_unref (output_state);
231 goto failed_unref_buffer2;
234 gst_msdk_update_mfx_frame_info_from_mfx_video_param (&i->surface->Info,
236 thiz->decoded_msdk_surfaces = g_list_append (thiz->decoded_msdk_surfaces, i);
239 failed_unref_buffer2:
240 gst_buffer_unref (buffer);
241 buffer = i->data.buffer;
243 gst_video_frame_unmap (&i->copy);
245 gst_buffer_unref (buffer);
246 g_slice_free (MsdkSurface, i);
248 GST_ERROR_OBJECT (thiz, "failed to handle buffer");
253 gst_msdkdec_close_decoder (GstMsdkDec * thiz, gboolean reset_param)
257 if (!thiz->context || !thiz->initialized)
260 GST_DEBUG_OBJECT (thiz, "Closing decoder with context %" GST_PTR_FORMAT,
263 if (thiz->use_video_memory)
264 gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
266 status = MFXVideoDECODE_Close (gst_msdk_context_get_session (thiz->context));
267 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
268 GST_WARNING_OBJECT (thiz, "Decoder close failed (%s)",
269 msdk_status_to_string (status));
272 g_array_set_size (thiz->tasks, 0);
275 memset (&thiz->param, 0, sizeof (thiz->param));
277 thiz->initialized = FALSE;
278 gst_adapter_clear (thiz->adapter);
282 gst_msdkdec_set_context (GstElement * element, GstContext * context)
284 GstMsdkContext *msdk_context = NULL;
285 GstMsdkDec *thiz = GST_MSDKDEC (element);
287 if (gst_msdk_context_get_context (context, &msdk_context)) {
288 gst_object_replace ((GstObject **) & thiz->context,
289 (GstObject *) msdk_context);
290 gst_object_unref (msdk_context);
293 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
297 gst_msdkdec_init_decoder (GstMsdkDec * thiz)
299 GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
303 mfxFrameAllocRequest request;
305 if (thiz->initialized)
308 if (!thiz->context) {
309 GST_WARNING_OBJECT (thiz, "No MSDK Context");
313 if (!thiz->input_state) {
314 GST_DEBUG_OBJECT (thiz, "Have no input state yet");
317 info = &thiz->input_state->info;
319 GST_OBJECT_LOCK (thiz);
321 if (thiz->use_video_memory) {
322 gst_msdk_set_frame_allocator (thiz->context);
323 thiz->param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
325 thiz->param.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
328 GST_INFO_OBJECT (thiz, "This MSDK decoder uses %s memory",
329 thiz->use_video_memory ? "video" : "system");
331 thiz->param.AsyncDepth = thiz->async_depth;
333 /* We expect msdk to fill the width and height values */
334 g_return_val_if_fail (thiz->param.mfx.FrameInfo.Width
335 && thiz->param.mfx.FrameInfo.Height, FALSE);
337 klass->preinit_decoder (thiz);
339 /* Set frame rate only if provided.
340 * If not, frame rate will be assumed inside the driver.
341 * Also we respect the upstream provided fps values */
342 if (info->fps_n > 0 && info->fps_d > 0
343 && info->fps_n != thiz->param.mfx.FrameInfo.FrameRateExtN
344 && info->fps_d != thiz->param.mfx.FrameInfo.FrameRateExtD) {
345 thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
346 thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
349 if (info->par_n && info->par_d && !thiz->param.mfx.FrameInfo.AspectRatioW
350 && !thiz->param.mfx.FrameInfo.AspectRatioH) {
351 thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
352 thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
355 thiz->param.mfx.FrameInfo.FourCC =
356 thiz->param.mfx.FrameInfo.FourCC ? thiz->param.mfx.
357 FrameInfo.FourCC : MFX_FOURCC_NV12;
358 thiz->param.mfx.FrameInfo.ChromaFormat =
359 thiz->param.mfx.FrameInfo.ChromaFormat ? thiz->param.mfx.
360 FrameInfo.ChromaFormat : MFX_CHROMAFORMAT_YUV420;
362 session = gst_msdk_context_get_session (thiz->context);
363 /* validate parameters and allow the Media SDK to make adjustments */
364 status = MFXVideoDECODE_Query (session, &thiz->param, &thiz->param);
365 if (status < MFX_ERR_NONE) {
366 GST_ERROR_OBJECT (thiz, "Video Decode Query failed (%s)",
367 msdk_status_to_string (status));
369 } else if (status > MFX_ERR_NONE) {
370 GST_WARNING_OBJECT (thiz, "Video Decode Query returned: %s",
371 msdk_status_to_string (status));
374 klass->postinit_decoder (thiz);
376 status = MFXVideoDECODE_QueryIOSurf (session, &thiz->param, &request);
377 if (status < MFX_ERR_NONE) {
378 GST_ERROR_OBJECT (thiz, "Query IO surfaces failed (%s)",
379 msdk_status_to_string (status));
381 } else if (status > MFX_ERR_NONE) {
382 GST_WARNING_OBJECT (thiz, "Query IO surfaces returned: %s",
383 msdk_status_to_string (status));
386 if (request.NumFrameSuggested < thiz->param.AsyncDepth) {
387 GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
388 request.NumFrameMin, request.NumFrameSuggested, thiz->param.AsyncDepth);
392 /* account for downstream requirement */
393 if (G_LIKELY (thiz->min_prealloc_buffers))
394 request.NumFrameSuggested += thiz->min_prealloc_buffers;
396 GST_WARNING_OBJECT (thiz,
397 "Allocating resources without considering the downstream requirement"
398 "or extra scratch surface count");
400 if (thiz->use_video_memory) {
401 gint shared_async_depth;
404 gst_msdk_context_get_shared_async_depth (thiz->context);
405 request.NumFrameSuggested += shared_async_depth;
407 request.Type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
408 if (thiz->use_dmabuf)
409 request.Type |= MFX_MEMTYPE_EXPORT_FRAME;
410 gst_msdk_frame_alloc (thiz->context, &request, &thiz->alloc_resp);
413 /* update the prealloc_buffer count, which will be used later
414 * as GstBufferPool min_buffers */
415 thiz->min_prealloc_buffers = request.NumFrameSuggested;
417 GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested)",
418 request.NumFrameMin, request.NumFrameSuggested);
420 status = MFXVideoDECODE_Init (session, &thiz->param);
421 if (status < MFX_ERR_NONE) {
422 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
424 } else if (status > MFX_ERR_NONE) {
425 GST_WARNING_OBJECT (thiz, "Init returned: %s",
426 msdk_status_to_string (status));
429 status = MFXVideoDECODE_GetVideoParam (session, &thiz->param);
430 if (status < MFX_ERR_NONE) {
431 GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
432 msdk_status_to_string (status));
434 } else if (status > MFX_ERR_NONE) {
435 GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
436 msdk_status_to_string (status));
439 g_array_set_size (thiz->tasks, 0); /* resets array content */
440 g_array_set_size (thiz->tasks, thiz->param.AsyncDepth);
443 GST_OBJECT_UNLOCK (thiz);
445 thiz->initialized = TRUE;
449 GST_OBJECT_UNLOCK (thiz);
455 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
459 for (i = 0; i < gst_caps_get_size (caps); i++) {
460 GstCapsFeatures *const features = gst_caps_get_features (caps, i);
461 /* Skip ANY features, we need an exact match for correct evaluation */
462 if (gst_caps_features_is_any (features))
464 if (gst_caps_features_contains (features, feature))
472 srcpad_can_dmabuf (GstMsdkDec * thiz)
474 gboolean ret = FALSE;
475 GstCaps *caps, *out_caps;
478 srcpad = GST_VIDEO_DECODER_SRC_PAD (thiz);
479 caps = gst_pad_get_pad_template_caps (srcpad);
481 out_caps = gst_pad_peer_query_caps (srcpad, caps);
485 if (gst_caps_is_any (out_caps) || gst_caps_is_empty (out_caps)
489 if (_gst_caps_has_feature (out_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
494 gst_caps_unref (caps);
496 gst_caps_unref (out_caps);
501 gst_msdkdec_set_src_caps (GstMsdkDec * thiz, gboolean need_allocation)
503 GstVideoCodecState *output_state;
505 GstVideoAlignment align;
506 GstCaps *allocation_caps = NULL;
507 GstVideoFormat format;
509 guint alloc_w, alloc_h;
510 const gchar *format_str;
512 /* use display width and display height in output state, which
513 * will be used for caps negotiation */
515 thiz->param.mfx.FrameInfo.CropW ? thiz->param.mfx.
516 FrameInfo.CropW : GST_VIDEO_INFO_WIDTH (&thiz->input_state->info);
518 thiz->param.mfx.FrameInfo.CropH ? thiz->param.mfx.
519 FrameInfo.CropH : GST_VIDEO_INFO_HEIGHT (&thiz->input_state->info);
522 gst_msdk_get_video_format_from_mfx_fourcc (thiz->param.mfx.
525 if (format == GST_VIDEO_FORMAT_UNKNOWN) {
526 GST_WARNING_OBJECT (thiz, "Failed to find a valid video format");
531 gst_video_decoder_set_output_state (GST_VIDEO_DECODER (thiz),
532 format, width, height, thiz->input_state);
536 /* Find allocation width and height */
538 GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
539 FrameInfo.Width : width);
541 GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
542 FrameInfo.Height : height);
544 /* Ensure output_state->caps and info have same width and height
545 * Also, mandate 32 bit alignment */
546 vinfo = &output_state->info;
547 gst_msdk_set_video_alignment (vinfo, alloc_w, alloc_h, &align);
548 gst_video_info_align (vinfo, &align);
549 output_state->caps = gst_video_info_to_caps (vinfo);
550 if (srcpad_can_dmabuf (thiz))
551 gst_caps_set_features (output_state->caps, 0,
552 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
554 if (need_allocation) {
555 /* Find allocation width and height */
557 GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
558 FrameInfo.Width : GST_VIDEO_INFO_WIDTH (&output_state->info));
560 GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
561 FrameInfo.Height : GST_VIDEO_INFO_HEIGHT (&output_state->info));
563 /* set allocation width and height in allocation_caps,
564 * which may or may not be similar to the output_state caps */
565 allocation_caps = gst_caps_copy (output_state->caps);
567 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
568 (&output_state->info));
569 gst_caps_set_simple (allocation_caps, "width", G_TYPE_INT, width, "height",
570 G_TYPE_INT, height, "format", G_TYPE_STRING, format_str, NULL);
571 GST_INFO_OBJECT (thiz, "new alloc caps = %" GST_PTR_FORMAT,
573 gst_caps_replace (&output_state->allocation_caps, allocation_caps);
574 gst_caps_unref (allocation_caps);
576 /* We keep the allocation parameters as it is to avoid pool re-negotiation.
577 * For codecs like VP9, dynamic resolution change doesn't require allocation
578 * reset if the new video frame resolution is lower than the
579 * already configured one */
581 gst_video_codec_state_unref (output_state);
587 gst_msdkdec_set_latency (GstMsdkDec * thiz)
589 GstVideoInfo *info = &thiz->input_state->info;
590 gint min_delayed_frames;
591 GstClockTime latency;
593 min_delayed_frames = thiz->async_depth;
596 latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
597 min_delayed_frames, info->fps_n);
599 /* FIXME: Assume 25fps. This is better than reporting no latency at
600 * all and then later failing in live pipelines
602 latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
603 min_delayed_frames, 25);
606 GST_INFO_OBJECT (thiz,
607 "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
608 GST_TIME_ARGS (latency), min_delayed_frames);
610 gst_video_decoder_set_latency (GST_VIDEO_DECODER (thiz), latency, latency);
614 _find_msdk_surface (gconstpointer msdk_surface, gconstpointer comp_surface)
616 MsdkSurface *cached_surface = (MsdkSurface *) msdk_surface;
617 mfxFrameSurface1 *_surface = (mfxFrameSurface1 *) comp_surface;
619 return cached_surface ? cached_surface->surface != _surface : -1;
623 gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
625 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
627 GstVideoCodecFrame *frame;
628 MsdkSurface *surface;
631 guint64 pts = MFX_TIMESTAMP_UNKNOWN;
633 if (G_LIKELY (task->sync_point)) {
635 MFXVideoCORE_SyncOperation (gst_msdk_context_get_session
636 (thiz->context), task->sync_point, 300000);
637 if (status != MFX_ERR_NONE) {
638 GST_ERROR_OBJECT (thiz, "failed to do sync operation");
639 return GST_FLOW_ERROR;
644 GST_DEBUG_OBJECT (thiz, "Decoded MFX TimeStamp: %" G_GUINT64_FORMAT,
645 (guint64) task->surface->Data.TimeStamp);
646 pts = task->surface->Data.TimeStamp;
649 if (G_LIKELY (task->sync_point || (task->surface && task->decode_only))) {
650 gboolean decode_only = task->decode_only;
652 frame = gst_msdkdec_get_oldest_frame (decoder);
653 /* align decoder frame list with current decoded position */
654 while (frame && MFX_TIME_IS_VALID (pts)
655 && GST_CLOCK_TIME_IS_VALID (frame->pts)
656 && GST_TO_MFX_TIME (frame->pts) < pts) {
657 GST_INFO_OBJECT (thiz, "Discarding frame: %p PTS: %" GST_TIME_FORMAT
658 " MFX TimeStamp: %" G_GUINT64_FORMAT,
659 frame, GST_TIME_ARGS (frame->pts), GST_TO_MFX_TIME (frame->pts));
660 gst_video_decoder_release_frame (decoder, frame);
661 frame = gst_msdkdec_get_oldest_frame (decoder);
664 l = g_list_find_custom (thiz->decoded_msdk_surfaces, task->surface,
669 GST_ERROR_OBJECT (thiz, "Couldn't find the cached MSDK surface");
670 return GST_FLOW_ERROR;
673 if (G_LIKELY (frame)) {
674 if (G_LIKELY (surface->copy.buffer == NULL)) {
675 frame->output_buffer = gst_buffer_ref (surface->buf);
677 gst_video_frame_copy (&surface->copy, &surface->data);
678 frame->output_buffer = gst_buffer_ref (surface->copy.buffer);
680 GST_DEBUG_OBJECT (thiz, "surface %p TimeStamp: %" G_GUINT64_FORMAT
681 " frame %p TimeStamp: %" G_GUINT64_FORMAT,
682 surface->surface, (guint64) surface->surface->Data.TimeStamp,
683 frame, GST_TO_MFX_TIME (frame->pts));
686 if (!thiz->postpone_free_surface)
687 free_surface (thiz, surface);
688 task->sync_point = NULL;
689 task->surface = NULL;
690 task->decode_only = FALSE;
693 return GST_FLOW_FLUSHING;
696 GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
697 flow = gst_video_decoder_finish_frame (decoder, frame);
698 if (flow == GST_FLOW_ERROR)
699 GST_ERROR_OBJECT (thiz, "Failed to finish frame");
706 gst_msdkdec_start (GstVideoDecoder * decoder)
708 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
710 if (gst_msdk_context_prepare (GST_ELEMENT_CAST (thiz), &thiz->context)) {
711 GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
714 /* TODO: Currently d3d allocator is not implemented.
715 * So decoder uses system memory by default on Windows.
718 thiz->use_video_memory = TRUE;
720 thiz->use_video_memory = FALSE;
723 if (gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_DECODER) {
724 GstMsdkContext *parent_context, *msdk_context;
726 parent_context = thiz->context;
727 msdk_context = gst_msdk_context_new_with_parent (parent_context);
730 GST_ERROR_OBJECT (thiz, "Context creation failed");
734 thiz->context = msdk_context;
736 gst_msdk_context_add_shared_async_depth (thiz->context,
737 gst_msdk_context_get_shared_async_depth (parent_context));
738 gst_object_unref (parent_context);
740 GST_INFO_OBJECT (thiz,
741 "Creating new context %" GST_PTR_FORMAT " with joined session",
744 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_DECODER);
747 if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
748 thiz->hardware, GST_MSDK_JOB_DECODER))
750 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
754 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
760 gst_msdkdec_close (GstVideoDecoder * decoder)
762 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
765 gst_object_replace ((GstObject **) & thiz->context, NULL);
771 gst_msdkdec_stop (GstVideoDecoder * decoder)
773 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
775 gst_msdkdec_flush (decoder);
777 if (thiz->input_state) {
778 gst_video_codec_state_unref (thiz->input_state);
779 thiz->input_state = NULL;
782 gst_object_unref (thiz->pool);
785 gst_video_info_init (&thiz->non_msdk_pool_info);
787 gst_msdkdec_close_decoder (thiz, TRUE);
792 gst_msdkdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
794 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
796 if (thiz->input_state) {
797 /* mark for re-negotiation if display resolution or any other video info
798 * changes like framerate. */
799 if (!gst_video_info_is_equal (&thiz->input_state->info, &state->info)) {
800 GST_INFO_OBJECT (thiz, "Schedule renegotiation as video info changed");
801 thiz->do_renego = TRUE;
803 gst_video_codec_state_unref (thiz->input_state);
805 thiz->input_state = gst_video_codec_state_ref (state);
807 /* we don't set output state here to avoid caching of mismatched
808 * video information if there is dynamic resolution change in the stream.
809 * All negotiation code is consolidated in gst_msdkdec_negotiate() and
810 * this will be invoked from handle_frame() */
812 gst_msdkdec_set_latency (thiz);
817 release_msdk_surfaces (GstMsdkDec * thiz)
820 MsdkSurface *surface;
822 for (l = thiz->decoded_msdk_surfaces; l;) {
825 free_surface (thiz, surface);
829 /* This will get invoked in the following situations:
830 * 1: beginning of the stream, which requires initialization (== complete reset)
831 * 2: upstream notified a resolution change and set do_renego to TRUE.
832 * new resolution may or may not requires full reset
833 * 3: upstream failed to notify the resolution change but
834 * msdk detected the change (eg: vp9 stream in ivf elementary form
835 * with varying resolution frames).
837 * for any input configuration change, we deal with notification
838 * from upstream and also use msdk APIs to handle the parameter initialization
842 gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset)
844 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
845 GST_DEBUG_OBJECT (thiz,
846 "Start Negotiating caps, pool and Init the msdk decdoer subsystem");
849 /* Retrieve any pending frames and push them downstream */
850 if (gst_msdkdec_drain (GST_VIDEO_DECODER (thiz)) != GST_FLOW_OK)
853 /* This will initiate the allocation query which will help to flush
854 * all the pending buffers in the pipeline so that we can stop
855 * the active bufferpool and safely invoke gst_msdk_frame_free() */
856 if (thiz->initialized) {
857 GstCaps *caps = gst_pad_get_current_caps (decoder->srcpad);
858 GstQuery *query = NULL;
860 query = gst_query_new_allocation (caps, FALSE);
861 gst_pad_peer_query (decoder->srcpad, query);
862 gst_query_unref (query);
863 gst_caps_unref (caps);
867 /* De-initialize the decoder if it is already active */
868 /* Do not reset the mfxVideoParam since it already
869 * has the required parameters for new session decode */
870 gst_msdkdec_close_decoder (thiz, FALSE);
872 /* request for pool re-negotiation by setting do_realloc */
873 thiz->do_realloc = TRUE;
876 /* At this point all pending frames (if there are any) are pushed downstream
877 * and we are ready to negotiate the output caps */
878 if (!gst_msdkdec_set_src_caps (thiz, hard_reset))
881 /* this will initiate the allocation query, we create the
882 * bufferpool in decide_allocation in order to account
883 * for the downstream min_buffer requirement
884 * Required initializations for MediaSDK operations
885 * will all be initialized from decide_allocation after considering
886 * some of the downstream requirements */
887 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (thiz)))
888 goto error_negotiate;
890 thiz->do_renego = FALSE;
891 thiz->do_realloc = FALSE;
896 GST_ERROR_OBJECT (thiz, "Failed to Drain the queued decoded frames");
900 GST_ERROR_OBJECT (thiz, "Failed to re-negotiate");
905 gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
907 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
908 GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
910 GstBuffer *buffer, *input_buffer = NULL;
911 GstVideoInfo alloc_info;
912 MsdkDecTask *task = NULL;
913 mfxBitstream bitstream;
914 MsdkSurface *surface = NULL;
918 guint i, retry_err_incompatible = 0;
920 gboolean hard_reset = FALSE;
921 GstClockTime pts = GST_CLOCK_TIME_NONE;
923 /* configure the subclass in order to fill the CodecID field of
924 * mfxVideoParam and also to load the PluginID for some of the
925 * codecs which is mandatory to invoke the
926 * MFXVideoDECODE_DecodeHeader API.
928 * For non packetized formats (currently only vc1), there
929 * could be headers received as codec_data which are not available
930 * instream and in that case subclass implementation will
931 * push it to the internal adapter. We invoke the subclass configure
932 * well early to make sure the codec_data received has been correctly
933 * pushed to the adapter by the subclasses before doing
934 * the DecodeHeader() later on
936 if (!thiz->initialized || thiz->do_renego) {
937 /* Clear the internal adapter in re-negotiation for non-packetized
939 if (!gst_video_decoder_get_packetized (decoder))
940 gst_adapter_clear (thiz->adapter);
942 if (!klass->configure || !klass->configure (thiz)) {
948 /* Current frame-codec could be pushed and released before this
949 * function ends -- because msdkdec pushes the oldest frame,
950 * according its PTS, and it could be this very same frame-codec
951 * among others pending frame-codecs.
953 * Instead of copying the input data into the mfxBitstream, let's
954 * keep an extra reference to frame-codec's input buffer */
955 input_buffer = gst_buffer_ref (frame->input_buffer);
956 if (!gst_buffer_map (input_buffer, &map_info, GST_MAP_READ)) {
957 gst_buffer_unref (input_buffer);
958 return GST_FLOW_ERROR;
961 memset (&bitstream, 0, sizeof (bitstream));
963 if (gst_video_decoder_get_packetized (decoder)) {
964 /* Packetized stream: we prefer to have a parser as a connected upstream
965 * element to the decoder */
967 bitstream.Data = map_info.data;
968 bitstream.DataLength = map_info.size;
969 bitstream.MaxLength = map_info.size;
970 bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
973 * MFX_BITSTREAM_COMPLETE_FRAME was removed since commit df59db9, however
974 * some customers still use DecodedOrder (deprecated in msdk-2017 version)
975 * for low-latency streaming of non-b-frame encoded streams, which needs to
976 * output the frame at once, so add it back for this case
978 if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
979 bitstream.DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME;
981 /* Non packetized streams: eg: vc1 advanced profile with per buffer bdu */
982 gst_adapter_push (thiz->adapter, gst_buffer_ref (input_buffer));
983 data_size = gst_adapter_available (thiz->adapter);
985 bitstream.Data = (mfxU8 *) gst_adapter_map (thiz->adapter, data_size);
986 bitstream.DataLength = (mfxU32) data_size;
987 bitstream.MaxLength = bitstream.DataLength;
988 bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
990 GST_DEBUG_OBJECT (thiz,
991 "mfxBitStream=> DataLength:%d DataOffset:%d MaxLength:%d "
992 "PTS: %" GST_TIME_FORMAT " MFX TimeStamp %" G_GUINT64_FORMAT,
993 bitstream.DataLength, bitstream.DataOffset, bitstream.MaxLength,
994 GST_TIME_ARGS (pts), (guint64) bitstream.TimeStamp);
996 session = gst_msdk_context_get_session (thiz->context);
998 if (!thiz->initialized || thiz->do_renego) {
1000 /* gstreamer caps will not provide all the necessary parameters
1001 * required for optimal decode configuration. For example: the required number
1002 * of surfaces to be allocated can be calculated based on H264 SEI header
1003 * and this information can't be retrieved from the negotiated caps.
1004 * So instead of introducing a codecparser dependency to parse the headers
1005 * inside msdk plugin, we simply use the mfx APIs to extract header information */
1006 status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1007 GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1008 if (status == MFX_ERR_MORE_DATA) {
1013 if (!klass->post_configure (thiz)) {
1014 flow = GST_FLOW_ERROR;
1018 if (!thiz->initialized)
1021 GstVideoCodecState *output_state =
1022 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1024 if (output_state->allocation_caps) {
1025 gst_video_info_from_caps (&alloc_info, output_state->allocation_caps);
1027 /* Check whether we need complete reset for dynamic resolution change */
1028 if (thiz->param.mfx.FrameInfo.Width >
1029 GST_VIDEO_INFO_WIDTH (&alloc_info)
1030 || thiz->param.mfx.FrameInfo.Height >
1031 GST_VIDEO_INFO_HEIGHT (&alloc_info))
1034 gst_video_codec_state_unref (output_state);
1039 /* if subclass requested for the force reset */
1040 if (thiz->force_reset_on_res_change)
1043 if (!gst_msdkdec_negotiate (thiz, hard_reset)) {
1044 GST_ELEMENT_ERROR (thiz, CORE, NEGOTIATION,
1045 ("Could not negotiate the stream"), (NULL));
1046 flow = GST_FLOW_ERROR;
1051 /* gst_msdkdec_handle_frame owns one ref on input argument |frame|. At this
1052 * point this frame is not used so just unref it right away.
1053 * gst_msdkdec_finish_task is fetching the frames itself. */
1054 gst_video_codec_frame_unref (frame);
1057 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1058 flow = gst_msdkdec_finish_task (thiz, task);
1059 if (flow != GST_FLOW_OK) {
1060 if (flow == GST_FLOW_ERROR)
1061 GST_ERROR_OBJECT (thiz, "Failed to finish a task");
1065 flow = allocate_output_buffer (thiz, &buffer);
1066 if (flow == GST_FLOW_CUSTOM_SUCCESS) {
1069 } else if (flow != GST_FLOW_OK)
1071 surface = get_surface (thiz, buffer);
1073 /* Can't get a surface for some reason; finish tasks, then see if
1074 a surface becomes available. */
1075 for (i = 0; i < thiz->tasks->len - 1; i++) {
1076 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1077 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1078 flow = gst_msdkdec_finish_task (thiz, task);
1079 if (flow != GST_FLOW_OK)
1081 surface = get_surface (thiz, buffer);
1086 GST_ERROR_OBJECT (thiz, "Couldn't get a surface");
1087 flow = GST_FLOW_ERROR;
1094 MFXVideoDECODE_DecodeFrameAsync (session, &bitstream, surface->surface,
1095 &task->surface, &task->sync_point);
1096 GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1098 /* media-sdk requires complete reset since the surface is inadequate
1099 * for further decoding */
1100 if (status == MFX_ERR_INCOMPATIBLE_VIDEO_PARAM &&
1101 retry_err_incompatible++ < 1) {
1102 /* MFX_ERR_INCOMPATIBLE_VIDEO_PARAM means the current mfx surface is not
1103 * suitable for the current frame. Call MFXVideoDECODE_DecodeHeader to get
1104 * the current frame size, then do memory re-allocation, otherwise
1105 * MFXVideoDECODE_DecodeFrameAsync will still fail on next call */
1106 status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1107 GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1108 if (status == MFX_ERR_MORE_DATA) {
1113 /* Requires memory re-allocation, do a hard reset */
1114 if (!gst_msdkdec_negotiate (thiz, TRUE))
1117 /* The current surface is freed when doing a hard reset; a new surface is
1118 * required for the new resolution */
1123 retry_err_incompatible = 0;
1125 if (G_LIKELY (status == MFX_ERR_NONE)
1126 || (status == MFX_WRN_VIDEO_PARAM_CHANGED)) {
1127 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1129 if (surface->surface->Data.Locked > 0)
1131 else if (!thiz->use_video_memory) {
1132 /* The for loop will continue because DataLength is greater than 0 so
1133 * free the surface right away if not in use. */
1134 if (bitstream.DataLength > 0 && task->surface != surface->surface)
1135 free_surface (thiz, surface);
1139 if (bitstream.DataLength == 0) {
1142 /* Don't release it if the current surface is in use */
1143 if (surface && task->surface == surface->surface)
1148 } else if (status == MFX_ERR_MORE_DATA) {
1149 if (task->surface) {
1150 task->decode_only = TRUE;
1151 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1154 if (surface->surface->Data.Locked > 0)
1156 flow = GST_VIDEO_DECODER_FLOW_NEED_DATA;
1158 } else if (status == MFX_ERR_MORE_SURFACE) {
1161 } else if (status == MFX_WRN_DEVICE_BUSY) {
1162 /* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
1165 if (task->surface &&
1166 task->surface == surface->surface && !task->sync_point) {
1167 free_surface (thiz, surface);
1171 /* If the current surface is still busy, we should do sync operation,
1172 * then try to decode again
1174 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1175 } else if (status < MFX_ERR_NONE) {
1176 GST_ERROR_OBJECT (thiz, "DecodeFrameAsync failed (%s)",
1177 msdk_status_to_string (status));
1178 flow = GST_FLOW_ERROR;
1183 if (!gst_video_decoder_get_packetized (decoder)) {
1184 /* flush out the data which has already been consumed by msdk */
1185 gst_adapter_flush (thiz->adapter, bitstream.DataOffset);
1189 * DecodedOrder was deprecated in msdk-2017 version, but some
1190 * customers still using this for low-latency streaming of non-b-frame
1191 * encoded streams, which needs to output the frame at once
1193 if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
1194 gst_msdkdec_finish_task (thiz, task);
1198 free_surface (thiz, surface);
1200 gst_buffer_unmap (input_buffer, &map_info);
1201 gst_buffer_unref (input_buffer);
1206 gst_buffer_unmap (input_buffer, &map_info);
1207 gst_buffer_unref (input_buffer);
1210 gst_video_decoder_drop_frame (decoder, frame);
1215 static GstFlowReturn
1216 gst_msdkdec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame,
1217 GstAdapter * adapter, gboolean at_eos)
1222 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1224 /* Don't parse the input buffer indeed, it will invoke
1225 * gst_msdkdec_handle_frame to handle the input buffer */
1226 size = gst_adapter_available (adapter);
1227 gst_video_decoder_add_to_frame (decoder, size);
1228 ret = gst_video_decoder_have_frame (decoder);
1229 size = gst_adapter_available (thiz->adapter);
1232 /* The base class will set up a new frame for parsing as
1233 * soon as there is valid data in the buffer */
1234 buffer = gst_adapter_get_buffer (thiz->adapter, size);
1235 gst_adapter_flush (thiz->adapter, size);
1236 gst_adapter_push (adapter, buffer);
1242 static GstBufferPool *
1243 gst_msdkdec_create_buffer_pool (GstMsdkDec * thiz, GstVideoInfo * info,
1246 GstBufferPool *pool = NULL;
1247 GstStructure *config;
1248 GstAllocator *allocator = NULL;
1249 GstVideoAlignment align;
1250 GstCaps *caps = NULL;
1251 GstAllocationParams params = { 0, 31, 0, 0, };
1252 mfxFrameAllocResponse *alloc_resp = NULL;
1254 g_return_val_if_fail (info, NULL);
1255 g_return_val_if_fail (GST_VIDEO_INFO_WIDTH (info)
1256 && GST_VIDEO_INFO_HEIGHT (info), NULL);
1258 alloc_resp = &thiz->alloc_resp;
1260 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
1264 caps = gst_video_info_to_caps (info);
1266 /* allocators should use the same width/height/stride/height_alignment of
1267 * negotiated output caps, which is what we configure in msdk_allocator */
1268 if (thiz->use_dmabuf)
1269 allocator = gst_msdk_dmabuf_allocator_new (thiz->context, info, alloc_resp);
1270 else if (thiz->use_video_memory)
1271 allocator = gst_msdk_video_allocator_new (thiz->context, info, alloc_resp);
1273 allocator = gst_msdk_system_allocator_new (info);
1276 gst_caps_unref (caps);
1277 goto error_no_allocator;
1280 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1281 gst_buffer_pool_config_set_params (config, caps,
1282 GST_VIDEO_INFO_SIZE (info), num_buffers, 0);
1283 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1284 gst_buffer_pool_config_add_option (config,
1285 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1286 gst_caps_unref (caps);
1288 if (thiz->use_video_memory) {
1289 gst_buffer_pool_config_add_option (config,
1290 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
1291 if (thiz->use_dmabuf)
1292 gst_buffer_pool_config_add_option (config,
1293 GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
1296 gst_buffer_pool_config_set_video_alignment (config, &align);
1297 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
1298 gst_object_unref (allocator);
1300 if (!gst_buffer_pool_set_config (pool, config))
1301 goto error_pool_config;
1307 GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1312 GST_INFO_OBJECT (thiz, "failed to create allocator");
1313 gst_object_unref (pool);
1318 GST_INFO_OBJECT (thiz, "failed to set config");
1319 gst_object_unref (pool);
1320 gst_object_unref (allocator);
1326 gst_msdkdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1328 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1329 GstBufferPool *pool = NULL;
1330 GstStructure *pool_config = NULL;
1331 GstCaps *pool_caps /*, *negotiated_caps */ ;
1332 guint size, min_buffers, max_buffers;
1334 if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
1338 /* Get the buffer pool config decided on by the base class. The base
1339 class ensures that there will always be at least a 0th pool in
1341 gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
1342 pool_config = gst_buffer_pool_get_config (pool);
1344 /* Get the caps of pool and increase the min and max buffers by async_depth.
1345 * We will always have that number of decode operations in-flight */
1346 gst_buffer_pool_config_get_params (pool_config, &pool_caps, &size,
1347 &min_buffers, &max_buffers);
1348 min_buffers += thiz->async_depth;
1350 max_buffers += thiz->async_depth;
1352 /* increase the min_buffers by 1 for smooth display in render pipeline */
1355 /* this will get updated with msdk requirement */
1356 thiz->min_prealloc_buffers = min_buffers;
1358 if (_gst_caps_has_feature (pool_caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
1359 GST_INFO_OBJECT (decoder, "This MSDK decoder uses DMABuf memory");
1360 thiz->use_video_memory = thiz->use_dmabuf = TRUE;
1363 /* Initialize MSDK decoder before new bufferpool tries to alloc each buffer,
1364 * which requires information about frame allocation.
1365 * No effect if already initialized.
1367 if (!gst_msdkdec_init_decoder (thiz))
1370 /* get the updated min_buffers, which account for the msdk requirement as well */
1371 min_buffers = thiz->min_prealloc_buffers;
1373 /* Decoder always use its own pool. So we create a pool if msdk APIs
1374 * previously requested for allocation (do_realloc = TRUE) */
1375 if (thiz->do_realloc || !thiz->pool) {
1376 GstVideoCodecState *output_state =
1377 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1379 gst_object_replace ((GstObject **) & thiz->pool, NULL);
1380 GST_INFO_OBJECT (decoder, "create new MSDK bufferpool");
1382 gst_msdkdec_create_buffer_pool (thiz, &output_state->info, min_buffers);
1383 gst_video_codec_state_unref (output_state);
1385 GST_ERROR_OBJECT (decoder, "failed to create new pool");
1386 goto failed_to_create_pool;
1390 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)
1391 && gst_buffer_pool_has_option (pool,
1392 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) {
1393 GstStructure *config;
1394 GstAllocator *allocator;
1396 /* If downstream supports video meta and video alignment,
1397 * we can replace with our own msdk bufferpool and use it
1399 /* Remove downstream's pool */
1400 gst_structure_free (pool_config);
1401 gst_object_unref (pool);
1403 pool = gst_object_ref (thiz->pool);
1405 /* Set the allocator of new msdk bufferpool */
1406 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1408 if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
1409 gst_query_set_nth_allocation_param (query, 0, allocator, NULL);
1410 gst_structure_free (config);
1412 /* Unfortunately, downstream doesn't have videometa or alignment support,
1413 * we keep msdk pool as a side-pool that will be decoded into and
1416 GstVideoCodecState *output_state = NULL;
1418 GST_INFO_OBJECT (decoder, "Keep MSDK bufferpool as a side-pool");
1420 /* Update params to downstream's pool */
1421 gst_buffer_pool_config_set_params (pool_config, pool_caps, size,
1422 min_buffers, max_buffers);
1423 if (!gst_buffer_pool_set_config (pool, pool_config))
1424 goto error_set_config;
1425 gst_video_info_from_caps (&thiz->non_msdk_pool_info, pool_caps);
1427 /* update width and height with actual negotiated values */
1429 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1430 GST_VIDEO_INFO_WIDTH (&thiz->non_msdk_pool_info) =
1431 GST_VIDEO_INFO_WIDTH (&output_state->info);
1432 GST_VIDEO_INFO_HEIGHT (&thiz->non_msdk_pool_info) =
1433 GST_VIDEO_INFO_HEIGHT (&output_state->info);
1434 gst_video_codec_state_unref (output_state);
1437 gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
1441 gst_object_unref (pool);
1446 failed_to_create_pool:
1447 GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1449 gst_object_unref (pool);
1453 GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1455 gst_object_unref (pool);
1459 static GstFlowReturn
1460 gst_msdkdec_drain (GstVideoDecoder * decoder)
1462 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1466 MsdkSurface *surface = NULL;
1471 if (!thiz->initialized)
1473 session = gst_msdk_context_get_session (thiz->context);
1476 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1477 if ((flow = gst_msdkdec_finish_task (thiz, task)) != GST_FLOW_OK) {
1478 if (flow != GST_FLOW_FLUSHING)
1479 GST_WARNING_OBJECT (decoder,
1480 "failed to finish the task %p, but keep draining for the remaining frames",
1485 flow = allocate_output_buffer (thiz, &buffer);
1486 if (flow != GST_FLOW_OK)
1488 surface = get_surface (thiz, buffer);
1490 return GST_FLOW_ERROR;
1494 MFXVideoDECODE_DecodeFrameAsync (session, NULL, surface->surface,
1495 &task->surface, &task->sync_point);
1496 GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1497 if (G_LIKELY (status == MFX_ERR_NONE)) {
1498 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1500 if (surface->surface->Data.Locked == 0)
1501 free_surface (thiz, surface);
1503 } else if (status == MFX_WRN_VIDEO_PARAM_CHANGED) {
1505 } else if (status == MFX_WRN_DEVICE_BUSY) {
1506 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1509 /* If the current surface is still busy, we should do sync operation,
1510 * then try to decode again
1512 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1513 } else if (status == MFX_ERR_MORE_DATA) {
1515 } else if (status == MFX_ERR_MORE_SURFACE) {
1518 } else if (status < MFX_ERR_NONE)
1519 return GST_FLOW_ERROR;
1522 free_surface (thiz, surface);
1524 for (i = 0; i < thiz->tasks->len; i++) {
1525 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1526 gst_msdkdec_finish_task (thiz, task);
1527 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1530 release_msdk_surfaces (thiz);
1536 gst_msdkdec_flush (GstVideoDecoder * decoder)
1538 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1541 ret = gst_msdkdec_drain (GST_VIDEO_DECODER_CAST (thiz));
1543 return ret == GST_FLOW_OK;
1546 static GstFlowReturn
1547 gst_msdkdec_finish (GstVideoDecoder * decoder)
1549 return gst_msdkdec_drain (decoder);
1553 gst_msdkdec_set_property (GObject * object, guint prop_id, const GValue * value,
1556 GstMsdkDec *thiz = GST_MSDKDEC (object);
1559 GST_OBJECT_LOCK (thiz);
1561 state = GST_STATE (thiz);
1562 if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1563 !(pspec->flags & GST_PARAM_MUTABLE_PLAYING))
1567 case GST_MSDKDEC_PROP_HARDWARE:
1568 thiz->hardware = g_value_get_boolean (value);
1570 case GST_MSDKDEC_PROP_ASYNC_DEPTH:
1571 thiz->async_depth = g_value_get_uint (value);
1574 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1577 GST_OBJECT_UNLOCK (thiz);
1583 GST_WARNING_OBJECT (thiz, "setting property in wrong state");
1584 GST_OBJECT_UNLOCK (thiz);
1589 gst_msdkdec_get_property (GObject * object, guint prop_id, GValue * value,
1592 GstMsdkDec *thiz = GST_MSDKDEC (object);
1594 GST_OBJECT_LOCK (thiz);
1596 case GST_MSDKDEC_PROP_HARDWARE:
1597 g_value_set_boolean (value, thiz->hardware);
1599 case GST_MSDKDEC_PROP_ASYNC_DEPTH:
1600 g_value_set_uint (value, thiz->async_depth);
1603 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1606 GST_OBJECT_UNLOCK (thiz);
1610 gst_msdkdec_finalize (GObject * object)
1612 GstMsdkDec *thiz = GST_MSDKDEC (object);
1614 g_array_unref (thiz->tasks);
1615 g_object_unref (thiz->adapter);
1617 /* NULL is the empty list. */
1618 if (G_UNLIKELY (thiz->decoded_msdk_surfaces != NULL)) {
1619 GST_ERROR_OBJECT (thiz, "leaking %u surfaces",
1620 g_list_length (thiz->decoded_msdk_surfaces));
1623 G_OBJECT_CLASS (parent_class)->finalize (object);
1627 gst_msdkdec_post_configure (GstMsdkDec * decoder)
1634 gst_msdkdec_preinit_decoder (GstMsdkDec * decoder)
1636 decoder->param.mfx.FrameInfo.Width =
1637 GST_ROUND_UP_16 (decoder->param.mfx.FrameInfo.Width);
1638 decoder->param.mfx.FrameInfo.Height =
1639 GST_ROUND_UP_32 (decoder->param.mfx.FrameInfo.Height);
1641 decoder->param.mfx.FrameInfo.PicStruct =
1642 decoder->param.mfx.FrameInfo.PicStruct ? decoder->param.mfx.
1643 FrameInfo.PicStruct : MFX_PICSTRUCT_PROGRESSIVE;
1649 gst_msdkdec_postinit_decoder (GstMsdkDec * decoder)
1656 gst_msdkdec_transform_meta (GstVideoDecoder * decoder,
1657 GstVideoCodecFrame * frame, GstMeta * meta)
1659 const GstMetaInfo *info = meta->info;
1661 if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (decoder, frame,
1665 if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta"))
1672 gst_msdkdec_class_init (GstMsdkDecClass * klass)
1674 GObjectClass *gobject_class;
1675 GstElementClass *element_class;
1676 GstVideoDecoderClass *decoder_class;
1678 gobject_class = G_OBJECT_CLASS (klass);
1679 element_class = GST_ELEMENT_CLASS (klass);
1680 decoder_class = GST_VIDEO_DECODER_CLASS (klass);
1682 gobject_class->set_property = gst_msdkdec_set_property;
1683 gobject_class->get_property = gst_msdkdec_get_property;
1684 gobject_class->finalize = gst_msdkdec_finalize;
1686 element_class->set_context = gst_msdkdec_set_context;
1688 decoder_class->close = GST_DEBUG_FUNCPTR (gst_msdkdec_close);
1689 decoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkdec_start);
1690 decoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkdec_stop);
1691 decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkdec_set_format);
1692 decoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkdec_finish);
1693 decoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkdec_handle_frame);
1694 decoder_class->parse = GST_DEBUG_FUNCPTR (gst_msdkdec_parse);
1695 decoder_class->decide_allocation =
1696 GST_DEBUG_FUNCPTR (gst_msdkdec_decide_allocation);
1697 decoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkdec_flush);
1698 decoder_class->drain = GST_DEBUG_FUNCPTR (gst_msdkdec_drain);
1699 decoder_class->transform_meta =
1700 GST_DEBUG_FUNCPTR (gst_msdkdec_transform_meta);
1702 klass->post_configure = GST_DEBUG_FUNCPTR (gst_msdkdec_post_configure);
1703 klass->preinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_preinit_decoder);
1704 klass->postinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_postinit_decoder);
1706 g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_HARDWARE,
1707 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware decoders",
1708 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1710 g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_ASYNC_DEPTH,
1711 g_param_spec_uint ("async-depth", "Async Depth",
1712 "Depth of asynchronous pipeline",
1713 1, 20, PROP_ASYNC_DEPTH_DEFAULT,
1714 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1716 gst_element_class_add_static_pad_template (element_class, &src_factory);
1720 gst_msdkdec_init (GstMsdkDec * thiz)
1722 gst_video_info_init (&thiz->non_msdk_pool_info);
1723 thiz->tasks = g_array_new (FALSE, TRUE, sizeof (MsdkDecTask));
1724 thiz->hardware = PROP_HARDWARE_DEFAULT;
1725 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1726 thiz->do_renego = TRUE;
1727 thiz->do_realloc = TRUE;
1728 thiz->force_reset_on_res_change = TRUE;
1729 thiz->postpone_free_surface = FALSE;
1730 thiz->adapter = gst_adapter_new ();
1731 thiz->input_state = NULL;
1733 thiz->context = NULL;
1734 thiz->decoded_msdk_surfaces = NULL;