1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2016, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 # include <config.h>
34 #endif
35
36 #include <stdlib.h>
37
38 #include "gstmsdkdec.h"
39 #include "gstmsdkbufferpool.h"
40 #include "gstmsdkvideomemory.h"
41 #include "gstmsdksystemmemory.h"
42 #include "gstmsdkcontextutil.h"
43
44 GST_DEBUG_CATEGORY_EXTERN (gst_msdkdec_debug);
45 #define GST_CAT_DEFAULT gst_msdkdec_debug
46
47 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
48 GST_PAD_SRC,
49 GST_PAD_ALWAYS,
50 GST_STATIC_CAPS (GST_MSDK_CAPS_STR ("NV12", "NV12"))
51 );
52
53 #define PROP_HARDWARE_DEFAULT TRUE
54 #define PROP_ASYNC_DEPTH_DEFAULT 1
55
56 #define IS_ALIGNED(i, n) (((i) & ((n)-1)) == 0)
57
58 #define GST_TO_MFX_TIME(time) ((time) == GST_CLOCK_TIME_NONE ? \
59 MFX_TIMESTAMP_UNKNOWN : gst_util_uint64_scale_round ((time), 9, 100000))
60
61 #define MFX_TIME_IS_VALID(time) ((time) != MFX_TIMESTAMP_UNKNOWN)
62
63 #define gst_msdkdec_parent_class parent_class
64 G_DEFINE_TYPE (GstMsdkDec, gst_msdkdec, GST_TYPE_VIDEO_DECODER);
65
66 typedef struct _MsdkSurface
67 {
68 mfxFrameSurface1 *surface;
69 GstBuffer *buf;
70 GstVideoFrame data;
71 GstVideoFrame copy;
72 } MsdkSurface;
73
74 struct _MsdkDecTask
75 {
76 MsdkSurface *surface;
77 mfxSyncPoint sync_point;
78
79 gboolean decode_only;
80 };
81
82 static gboolean gst_msdkdec_drain (GstVideoDecoder * decoder);
83 static gboolean gst_msdkdec_flush (GstVideoDecoder * decoder);
84 static gboolean gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset);
85
86 void
gst_msdkdec_add_bs_extra_param(GstMsdkDec * thiz,mfxExtBuffer * param)87 gst_msdkdec_add_bs_extra_param (GstMsdkDec * thiz, mfxExtBuffer * param)
88 {
89 if (thiz->num_bs_extra_params < MAX_BS_EXTRA_PARAMS) {
90 thiz->bs_extra_params[thiz->num_bs_extra_params] = param;
91 thiz->num_bs_extra_params++;
92 }
93 }
94
95 static GstVideoCodecFrame *
gst_msdkdec_get_oldest_frame(GstVideoDecoder * decoder)96 gst_msdkdec_get_oldest_frame (GstVideoDecoder * decoder)
97 {
98 GstVideoCodecFrame *frame = NULL, *old_frame = NULL;
99 GList *frames, *l;
100 gint count = 0;
101
102 frames = gst_video_decoder_get_frames (decoder);
103
104 for (l = frames; l != NULL; l = l->next) {
105 GstVideoCodecFrame *f = l->data;
106
107 if (!GST_CLOCK_TIME_IS_VALID (f->pts)) {
108 GST_INFO
109 ("Frame doesn't have a valid pts yet, Use gst_video_decoder_get_oldest_frame()"
110 "with out considering the PTS for selecting the frame to be finished");
111 old_frame = gst_video_decoder_get_oldest_frame (decoder);
112 break;
113 }
114
115 if (!frame || frame->pts > f->pts)
116 frame = f;
117
118 count++;
119 }
120
121 if (old_frame)
122 frame = old_frame;
123
124 if (frame) {
125 GST_LOG_OBJECT (decoder,
126 "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
127 frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
128 gst_video_codec_frame_ref (frame);
129 }
130
131 if (old_frame)
132 gst_video_codec_frame_unref (old_frame);
133
134 g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
135
136 return frame;
137 }
138
139 static inline void
free_surface(MsdkSurface * s)140 free_surface (MsdkSurface * s)
141 {
142 gst_buffer_unref (s->buf);
143 g_slice_free (MsdkSurface, s);
144 }
145
146 static void
unmap_frame(GstMsdkDec * thiz,MsdkSurface * s)147 unmap_frame (GstMsdkDec * thiz, MsdkSurface * s)
148 {
149 if (s->copy.buffer) {
150 /* we allocate this buffer from down stream, we need ref-1 for it */
151 gst_buffer_unref (s->copy.buffer);
152 gst_video_frame_unmap (&s->copy);
153 s->copy.buffer = NULL;
154 }
155
156 if (s->data.buffer) {
157 gst_video_frame_unmap (&s->data);
158 s->data.buffer = NULL;
159 }
160 }
161
162 static void
gst_msdkdec_free_unlocked_msdk_surfaces(GstMsdkDec * thiz)163 gst_msdkdec_free_unlocked_msdk_surfaces (GstMsdkDec * thiz)
164 {
165 GList *l;
166 MsdkSurface *surface;
167
168 for (l = thiz->locked_msdk_surfaces; l;) {
169 GList *next = l->next;
170 surface = l->data;
171 if (surface->surface->Data.Locked == 0) {
172 unmap_frame (thiz, surface);
173 free_surface (surface);
174 thiz->locked_msdk_surfaces =
175 g_list_delete_link (thiz->locked_msdk_surfaces, l);
176 }
177 l = next;
178 }
179 }
180
181 static GstFlowReturn
allocate_output_buffer(GstMsdkDec * thiz,GstBuffer ** buffer)182 allocate_output_buffer (GstMsdkDec * thiz, GstBuffer ** buffer)
183 {
184 GstFlowReturn flow;
185 GstVideoCodecFrame *frame;
186 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
187
188 frame = gst_msdkdec_get_oldest_frame (decoder);
189 if (!frame) {
190 if (GST_PAD_IS_FLUSHING (decoder->srcpad))
191 return GST_FLOW_FLUSHING;
192 else
193 return GST_FLOW_CUSTOM_SUCCESS;
194 }
195
196 if (!frame->output_buffer) {
197 /* Free un-unsed msdk surfaces firstly, hence the associated mfx
198 * surfaces will be moved from used list to available list */
199 gst_msdkdec_free_unlocked_msdk_surfaces (thiz);
200
201 flow = gst_video_decoder_allocate_output_frame (decoder, frame);
202 if (flow != GST_FLOW_OK) {
203 gst_video_codec_frame_unref (frame);
204 return flow;
205 }
206 }
207
208 *buffer = gst_buffer_ref (frame->output_buffer);
209 gst_buffer_replace (&frame->output_buffer, NULL);
210 gst_video_codec_frame_unref (frame);
211
212 return GST_FLOW_OK;
213 }
214
215 static MsdkSurface *
get_surface(GstMsdkDec * thiz,GstBuffer * buffer)216 get_surface (GstMsdkDec * thiz, GstBuffer * buffer)
217 {
218 MsdkSurface *i;
219 GstVideoCodecState *output_state = NULL;
220 gboolean success;
221
222 i = g_slice_new0 (MsdkSurface);
223
224 if (gst_msdk_is_msdk_buffer (buffer)) {
225 i->surface = gst_msdk_get_surface_from_buffer (buffer);
226 i->buf = buffer;
227 } else {
228 /* Confirm to activate the side pool */
229 if (!gst_buffer_pool_is_active (thiz->pool) &&
230 !gst_buffer_pool_set_active (thiz->pool, TRUE)) {
231 g_slice_free (MsdkSurface, i);
232 return NULL;
233 }
234
235 if (!gst_video_frame_map (&i->copy, &thiz->non_msdk_pool_info, buffer,
236 GST_MAP_WRITE))
237 goto failed_unref_buffer;
238
239 if (gst_buffer_pool_acquire_buffer (thiz->pool, &buffer,
240 NULL) != GST_FLOW_OK)
241 goto failed_unmap_copy;
242
243 i->surface = gst_msdk_get_surface_from_buffer (buffer);
244 i->buf = buffer;
245
246 output_state =
247 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
248 success =
249 gst_video_frame_map (&i->data, &output_state->info, buffer,
250 GST_MAP_READWRITE);
251 gst_video_codec_state_unref (output_state);
252 if (!success)
253 goto failed_unref_buffer2;
254 }
255
256 gst_msdk_update_mfx_frame_info_from_mfx_video_param (&i->surface->Info,
257 &thiz->param);
258
259 thiz->locked_msdk_surfaces = g_list_append (thiz->locked_msdk_surfaces, i);
260 return i;
261
262 failed_unref_buffer2:
263 gst_buffer_unref (buffer);
264 buffer = i->data.buffer;
265 failed_unmap_copy:
266 gst_video_frame_unmap (&i->copy);
267 failed_unref_buffer:
268 gst_buffer_unref (buffer);
269 g_slice_free (MsdkSurface, i);
270
271 GST_ERROR_OBJECT (thiz, "failed to handle buffer");
272 return NULL;
273 }
274
275 static void
gst_msdkdec_close_decoder(GstMsdkDec * thiz,gboolean reset_param)276 gst_msdkdec_close_decoder (GstMsdkDec * thiz, gboolean reset_param)
277 {
278 mfxStatus status;
279
280 if (!thiz->context || !thiz->initialized)
281 return;
282
283 GST_DEBUG_OBJECT (thiz, "Closing decoder with context %" GST_PTR_FORMAT,
284 thiz->context);
285
286 if (thiz->use_video_memory)
287 gst_msdk_frame_free (thiz->context, &thiz->alloc_resp);
288
289 status = MFXVideoDECODE_Close (gst_msdk_context_get_session (thiz->context));
290 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
291 GST_WARNING_OBJECT (thiz, "Decoder close failed (%s)",
292 msdk_status_to_string (status));
293 }
294
295 g_array_set_size (thiz->tasks, 0);
296
297 if (reset_param)
298 memset (&thiz->param, 0, sizeof (thiz->param));
299
300 thiz->num_bs_extra_params = 0;
301 thiz->initialized = FALSE;
302 gst_adapter_clear (thiz->adapter);
303 }
304
305 static void
gst_msdkdec_set_context(GstElement * element,GstContext * context)306 gst_msdkdec_set_context (GstElement * element, GstContext * context)
307 {
308 GstMsdkContext *msdk_context = NULL;
309 GstMsdkDec *thiz = GST_MSDKDEC (element);
310
311 if (gst_msdk_context_get_context (context, &msdk_context)) {
312 gst_object_replace ((GstObject **) & thiz->context,
313 (GstObject *) msdk_context);
314 gst_object_unref (msdk_context);
315 }
316
317 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
318 }
319
320 static gboolean
gst_msdkdec_init_decoder(GstMsdkDec * thiz)321 gst_msdkdec_init_decoder (GstMsdkDec * thiz)
322 {
323 GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
324 GstVideoInfo *info;
325 mfxSession session;
326 mfxStatus status;
327 mfxFrameAllocRequest request;
328
329 if (thiz->initialized)
330 return TRUE;
331
332 if (!thiz->context) {
333 GST_WARNING_OBJECT (thiz, "No MSDK Context");
334 return FALSE;
335 }
336
337 if (!thiz->input_state) {
338 GST_DEBUG_OBJECT (thiz, "Have no input state yet");
339 return FALSE;
340 }
341 info = &thiz->input_state->info;
342
343 GST_OBJECT_LOCK (thiz);
344
345 if (thiz->use_video_memory) {
346 gst_msdk_set_frame_allocator (thiz->context);
347 thiz->param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
348 } else {
349 thiz->param.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
350 }
351
352 GST_INFO_OBJECT (thiz, "This MSDK decoder uses %s memory",
353 thiz->use_video_memory ? "video" : "system");
354
355 thiz->param.AsyncDepth = thiz->async_depth;
356
357 /* We expect msdk to fill the width and height values */
358 g_return_val_if_fail (thiz->param.mfx.FrameInfo.Width
359 && thiz->param.mfx.FrameInfo.Height, FALSE);
360
361 klass->preinit_decoder (thiz);
362
363 /* Set frame rate only if provided.
364 * If not, frame rate will be assumed inside the driver.
365 * Also we respect the upstream provided fps values */
366 if (info->fps_n > 0 && info->fps_d > 0
367 && info->fps_n != thiz->param.mfx.FrameInfo.FrameRateExtN
368 && info->fps_d != thiz->param.mfx.FrameInfo.FrameRateExtD) {
369 thiz->param.mfx.FrameInfo.FrameRateExtN = info->fps_n;
370 thiz->param.mfx.FrameInfo.FrameRateExtD = info->fps_d;
371 }
372
373 if (info->par_n && info->par_d && !thiz->param.mfx.FrameInfo.AspectRatioW
374 && !thiz->param.mfx.FrameInfo.AspectRatioH) {
375 thiz->param.mfx.FrameInfo.AspectRatioW = info->par_n;
376 thiz->param.mfx.FrameInfo.AspectRatioH = info->par_d;
377 }
378
379 thiz->param.mfx.FrameInfo.FourCC =
380 thiz->param.mfx.FrameInfo.FourCC ? thiz->param.mfx.
381 FrameInfo.FourCC : MFX_FOURCC_NV12;
382 thiz->param.mfx.FrameInfo.ChromaFormat =
383 thiz->param.mfx.FrameInfo.ChromaFormat ? thiz->param.mfx.
384 FrameInfo.ChromaFormat : MFX_CHROMAFORMAT_YUV420;
385
386 session = gst_msdk_context_get_session (thiz->context);
387 /* validate parameters and allow MFX to make adjustments */
388 status = MFXVideoDECODE_Query (session, &thiz->param, &thiz->param);
389 if (status < MFX_ERR_NONE) {
390 GST_ERROR_OBJECT (thiz, "Video Decode Query failed (%s)",
391 msdk_status_to_string (status));
392 goto failed;
393 } else if (status > MFX_ERR_NONE) {
394 GST_WARNING_OBJECT (thiz, "Video Decode Query returned: %s",
395 msdk_status_to_string (status));
396 }
397
398 klass->postinit_decoder (thiz);
399
400 status = MFXVideoDECODE_QueryIOSurf (session, &thiz->param, &request);
401 if (status < MFX_ERR_NONE) {
402 GST_ERROR_OBJECT (thiz, "Query IO surfaces failed (%s)",
403 msdk_status_to_string (status));
404 goto failed;
405 } else if (status > MFX_ERR_NONE) {
406 GST_WARNING_OBJECT (thiz, "Query IO surfaces returned: %s",
407 msdk_status_to_string (status));
408 }
409
410 if (request.NumFrameSuggested < thiz->param.AsyncDepth) {
411 GST_ERROR_OBJECT (thiz, "Required %d surfaces (%d suggested), async %d",
412 request.NumFrameMin, request.NumFrameSuggested, thiz->param.AsyncDepth);
413 goto failed;
414 }
415
416 /* account for downstream requirement */
417 if (G_LIKELY (thiz->min_prealloc_buffers))
418 request.NumFrameSuggested += thiz->min_prealloc_buffers;
419 else
420 GST_WARNING_OBJECT (thiz,
421 "Allocating resources without considering the downstream requirement"
422 "or extra scratch surface count");
423
424 if (thiz->use_video_memory) {
425 gint shared_async_depth;
426
427 shared_async_depth =
428 gst_msdk_context_get_shared_async_depth (thiz->context);
429 request.NumFrameSuggested += shared_async_depth;
430
431 request.Type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
432 if (thiz->use_dmabuf)
433 request.Type |= MFX_MEMTYPE_EXPORT_FRAME;
434 gst_msdk_frame_alloc (thiz->context, &request, &thiz->alloc_resp);
435 }
436
437 /* update the prealloc_buffer count, which will be used later
438 * as GstBufferPool min_buffers */
439 thiz->min_prealloc_buffers = request.NumFrameSuggested;
440
441 GST_DEBUG_OBJECT (thiz, "Required %d surfaces (%d suggested)",
442 request.NumFrameMin, request.NumFrameSuggested);
443
444 status = MFXVideoDECODE_Init (session, &thiz->param);
445 if (status < MFX_ERR_NONE) {
446 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
447 goto failed;
448 } else if (status > MFX_ERR_NONE) {
449 GST_WARNING_OBJECT (thiz, "Init returned: %s",
450 msdk_status_to_string (status));
451 }
452
453 status = MFXVideoDECODE_GetVideoParam (session, &thiz->param);
454 if (status < MFX_ERR_NONE) {
455 GST_ERROR_OBJECT (thiz, "Get Video Parameters failed (%s)",
456 msdk_status_to_string (status));
457 goto failed;
458 } else if (status > MFX_ERR_NONE) {
459 GST_WARNING_OBJECT (thiz, "Get Video Parameters returned: %s",
460 msdk_status_to_string (status));
461 }
462
463 g_array_set_size (thiz->tasks, 0); /* resets array content */
464 g_array_set_size (thiz->tasks, thiz->param.AsyncDepth);
465 thiz->next_task = 0;
466
467 GST_OBJECT_UNLOCK (thiz);
468
469 thiz->initialized = TRUE;
470 return TRUE;
471
472 failed:
473 GST_OBJECT_UNLOCK (thiz);
474 return FALSE;
475 }
476
477
478 static gboolean
_gst_caps_has_feature(const GstCaps * caps,const gchar * feature)479 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
480 {
481 guint i;
482
483 for (i = 0; i < gst_caps_get_size (caps); i++) {
484 GstCapsFeatures *const features = gst_caps_get_features (caps, i);
485 /* Skip ANY features, we need an exact match for correct evaluation */
486 if (gst_caps_features_is_any (features))
487 continue;
488 if (gst_caps_features_contains (features, feature))
489 return TRUE;
490 }
491
492 return FALSE;
493 }
494
495 static gboolean
srcpad_can_dmabuf(GstMsdkDec * thiz)496 srcpad_can_dmabuf (GstMsdkDec * thiz)
497 {
498 gboolean ret = FALSE;
499 GstCaps *caps, *out_caps;
500 GstPad *srcpad;
501
502 srcpad = GST_VIDEO_DECODER_SRC_PAD (thiz);
503 caps = gst_pad_get_pad_template_caps (srcpad);
504
505 out_caps = gst_pad_peer_query_caps (srcpad, caps);
506 if (!out_caps)
507 goto done;
508
509 if (gst_caps_is_any (out_caps) || gst_caps_is_empty (out_caps)
510 || out_caps == caps)
511 goto done;
512
513 if (_gst_caps_has_feature (out_caps, GST_CAPS_FEATURE_MEMORY_DMABUF))
514 ret = TRUE;
515
516 done:
517 if (caps)
518 gst_caps_unref (caps);
519 if (out_caps)
520 gst_caps_unref (out_caps);
521 return ret;
522 }
523
524 static gboolean
gst_msdkdec_set_src_caps(GstMsdkDec * thiz,gboolean need_allocation)525 gst_msdkdec_set_src_caps (GstMsdkDec * thiz, gboolean need_allocation)
526 {
527 GstVideoCodecState *output_state;
528 GstVideoInfo *vinfo;
529 GstVideoAlignment align;
530 GstCaps *allocation_caps = NULL;
531 GstVideoFormat format;
532 guint width, height;
533 guint alloc_w, alloc_h;
534 const gchar *format_str;
535
536 /* use display width and display height in output state, which
537 * will be used for caps negotiation */
538 width =
539 thiz->param.mfx.FrameInfo.CropW ? thiz->param.mfx.
540 FrameInfo.CropW : GST_VIDEO_INFO_WIDTH (&thiz->input_state->info);
541 height =
542 thiz->param.mfx.FrameInfo.CropH ? thiz->param.mfx.
543 FrameInfo.CropH : GST_VIDEO_INFO_HEIGHT (&thiz->input_state->info);
544
545 format =
546 gst_msdk_get_video_format_from_mfx_fourcc (thiz->param.mfx.
547 FrameInfo.FourCC);
548
549 if (format == GST_VIDEO_FORMAT_UNKNOWN) {
550 GST_WARNING_OBJECT (thiz, "Failed to find a valid video format");
551 return FALSE;
552 }
553
554 output_state =
555 gst_video_decoder_set_output_state (GST_VIDEO_DECODER (thiz),
556 format, width, height, thiz->input_state);
557 if (!output_state)
558 return FALSE;
559
560 /* Find allocation width and height */
561 alloc_w =
562 GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
563 FrameInfo.Width : width);
564 alloc_h =
565 GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
566 FrameInfo.Height : height);
567
568 /* Ensure output_state->caps and info have same width and height
569 * Also, mandate 32 bit alignment */
570 vinfo = &output_state->info;
571 gst_msdk_set_video_alignment (vinfo, alloc_w, alloc_h, &align);
572 gst_video_info_align (vinfo, &align);
573 output_state->caps = gst_video_info_to_caps (vinfo);
574 if (srcpad_can_dmabuf (thiz))
575 gst_caps_set_features (output_state->caps, 0,
576 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
577
578 if (need_allocation) {
579 /* Find allocation width and height */
580 width =
581 GST_ROUND_UP_16 (thiz->param.mfx.FrameInfo.Width ? thiz->param.mfx.
582 FrameInfo.Width : GST_VIDEO_INFO_WIDTH (&output_state->info));
583 height =
584 GST_ROUND_UP_32 (thiz->param.mfx.FrameInfo.Height ? thiz->param.mfx.
585 FrameInfo.Height : GST_VIDEO_INFO_HEIGHT (&output_state->info));
586
587 /* set allocation width and height in allocation_caps,
588 * which may or may not be similar to the output_state caps */
589 allocation_caps = gst_caps_copy (output_state->caps);
590 format_str =
591 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
592 (&output_state->info));
593 gst_caps_set_simple (allocation_caps, "width", G_TYPE_INT, width, "height",
594 G_TYPE_INT, height, "format", G_TYPE_STRING, format_str, NULL);
595 GST_INFO_OBJECT (thiz, "new alloc caps = %" GST_PTR_FORMAT,
596 allocation_caps);
597 gst_caps_replace (&output_state->allocation_caps, allocation_caps);
598 gst_caps_unref (allocation_caps);
599 } else {
600 /* We keep the allocation parameters as it is to avoid pool re-negotiation.
601 * For codecs like VP9, dynamic resolution change doesn't require allocation
602 * reset if the new video frame resolution is lower than the
603 * already configured one */
604 }
605 gst_video_codec_state_unref (output_state);
606
607 return TRUE;
608 }
609
610 static void
gst_msdkdec_set_latency(GstMsdkDec * thiz)611 gst_msdkdec_set_latency (GstMsdkDec * thiz)
612 {
613 GstVideoInfo *info = &thiz->input_state->info;
614 gint min_delayed_frames;
615 GstClockTime latency;
616
617 min_delayed_frames = thiz->async_depth;
618
619 if (info->fps_n) {
620 latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
621 min_delayed_frames, info->fps_n);
622 } else {
623 /* FIXME: Assume 25fps. This is better than reporting no latency at
624 * all and then later failing in live pipelines
625 */
626 latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
627 min_delayed_frames, 25);
628 }
629
630 GST_INFO_OBJECT (thiz,
631 "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
632 GST_TIME_ARGS (latency), min_delayed_frames);
633
634 gst_video_decoder_set_latency (GST_VIDEO_DECODER (thiz), latency, latency);
635 }
636
637 static gint
_find_msdk_surface(gconstpointer msdk_surface,gconstpointer comp_surface)638 _find_msdk_surface (gconstpointer msdk_surface, gconstpointer comp_surface)
639 {
640 MsdkSurface *cached_surface = (MsdkSurface *) msdk_surface;
641 mfxFrameSurface1 *_surface = (mfxFrameSurface1 *) comp_surface;
642
643 return cached_surface ? cached_surface->surface != _surface : -1;
644 }
645
646 static void
finish_task(GstMsdkDec * thiz,MsdkDecTask * task)647 finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
648 {
649 MsdkSurface *surface = task->surface;
650 if (surface) {
651 if (G_UNLIKELY (surface->copy.buffer)) {
652 unmap_frame (thiz, surface);
653 }
654 thiz->locked_msdk_surfaces =
655 g_list_append (thiz->locked_msdk_surfaces, surface);
656 }
657 task->sync_point = NULL;
658 task->surface = NULL;
659 task->decode_only = FALSE;
660 }
661
662 static void
gst_msdkdec_frame_corruption_report(GstMsdkDec * thiz,mfxU16 corruption)663 gst_msdkdec_frame_corruption_report (GstMsdkDec * thiz, mfxU16 corruption)
664 {
665 if (!thiz->report_error || !corruption)
666 return;
667
668 if (corruption & MFX_CORRUPTION_MINOR)
669 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
670 ("[Corruption] Minor corruption detected!"), (NULL));
671
672 if (corruption & MFX_CORRUPTION_MAJOR)
673 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
674 ("[Corruption] Major corruption detected!"), (NULL));
675
676 if (corruption & MFX_CORRUPTION_ABSENT_TOP_FIELD)
677 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
678 ("[Corruption] Absent top field!"), (NULL));
679
680 if (corruption & MFX_CORRUPTION_ABSENT_BOTTOM_FIELD)
681 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
682 ("[Corruption] Absent bottom field!"), (NULL));
683
684 if (corruption & MFX_CORRUPTION_REFERENCE_FRAME)
685 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
686 ("[Corruption] Corrupted reference frame!"), (NULL));
687
688 if (corruption & MFX_CORRUPTION_REFERENCE_LIST)
689 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
690 ("[Corruption] Corrupted reference list!"), (NULL));
691 }
692
693 static GstFlowReturn
gst_msdkdec_finish_task(GstMsdkDec * thiz,MsdkDecTask * task)694 gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
695 {
696 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
697 GstFlowReturn flow;
698 GstVideoCodecFrame *frame;
699 MsdkSurface *surface;
700 mfxStatus status;
701 guint64 pts = MFX_TIMESTAMP_UNKNOWN;
702
703 if (G_LIKELY (task->sync_point)) {
704 status =
705 MFXVideoCORE_SyncOperation (gst_msdk_context_get_session
706 (thiz->context), task->sync_point, 300000);
707 if (status != MFX_ERR_NONE) {
708 GST_ERROR_OBJECT (thiz, "failed to do sync operation");
709 return GST_FLOW_ERROR;
710 }
711 }
712
713 surface = task->surface;
714 if (surface) {
715 gst_msdkdec_frame_corruption_report (thiz,
716 surface->surface->Data.Corrupted);
717 GST_DEBUG_OBJECT (thiz, "Decoded MFX TimeStamp: %" G_GUINT64_FORMAT,
718 (guint64) surface->surface->Data.TimeStamp);
719 pts = surface->surface->Data.TimeStamp;
720 }
721
722 if (G_LIKELY (task->sync_point || (surface && task->decode_only))) {
723 gboolean decode_only = task->decode_only;
724
725 frame = gst_msdkdec_get_oldest_frame (decoder);
726 /* align decoder frame list with current decoded position */
727 while (frame && MFX_TIME_IS_VALID (pts)
728 && GST_CLOCK_TIME_IS_VALID (frame->pts)
729 && GST_TO_MFX_TIME (frame->pts) < pts) {
730 GST_INFO_OBJECT (thiz, "Discarding frame: %p PTS: %" GST_TIME_FORMAT
731 " MFX TimeStamp: %" G_GUINT64_FORMAT,
732 frame, GST_TIME_ARGS (frame->pts), GST_TO_MFX_TIME (frame->pts));
733 gst_video_decoder_release_frame (decoder, frame);
734 frame = gst_msdkdec_get_oldest_frame (decoder);
735 }
736
737 if (G_LIKELY (frame)) {
738 if (G_LIKELY (surface->copy.buffer == NULL)) {
739 /* gst_video_decoder_finish_frame will call gst_buffer_make_writable
740 * we need this to avoid copy buffer */
741 GST_MINI_OBJECT_FLAG_SET (surface->buf, GST_MINI_OBJECT_FLAG_LOCKABLE);
742 frame->output_buffer = gst_buffer_ref (surface->buf);
743 } else {
744 gst_video_frame_copy (&surface->copy, &surface->data);
745 frame->output_buffer = gst_buffer_ref (surface->copy.buffer);
746 unmap_frame (thiz, surface);
747 }
748 GST_DEBUG_OBJECT (thiz, "surface %p TimeStamp: %" G_GUINT64_FORMAT
749 " frame %p TimeStamp: %" G_GUINT64_FORMAT,
750 surface->surface, (guint64) surface->surface->Data.TimeStamp,
751 frame, GST_TO_MFX_TIME (frame->pts));
752 }
753
754 finish_task (thiz, task);
755
756 if (!frame)
757 return GST_FLOW_FLUSHING;
758
759 if (decode_only)
760 GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
761 flow = gst_video_decoder_finish_frame (decoder, frame);
762 if (flow == GST_FLOW_ERROR)
763 GST_ERROR_OBJECT (thiz, "Failed to finish frame");
764 return flow;
765 }
766 finish_task (thiz, task);
767 return GST_FLOW_OK;
768 }
769
770 static gboolean
gst_msdkdec_context_prepare(GstMsdkDec * thiz)771 gst_msdkdec_context_prepare (GstMsdkDec * thiz)
772 {
773 /* Try to find an existing context from the pipeline. This may (indirectly)
774 * invoke gst_msdkdec_set_context, which will set thiz->context. */
775 if (!gst_msdk_context_find (GST_ELEMENT_CAST (thiz), &thiz->context))
776 return FALSE;
777
778 if (thiz->context == thiz->old_context) {
779 GST_INFO_OBJECT (thiz, "Found old context %" GST_PTR_FORMAT
780 ", reusing as-is", thiz->context);
781 return TRUE;
782 }
783
784 /* TODO: Currently d3d allocator is not implemented.
785 * So decoder uses system memory by default on Windows.
786 */
787 #ifndef _WIN32
788 thiz->use_video_memory = TRUE;
789 #else
790 thiz->use_video_memory = FALSE;
791 #endif
792
793 GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
794 thiz->context);
795
796 if (!(gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_DECODER)) {
797 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_DECODER);
798 return TRUE;
799 }
800
801 /* Found an existing context that's already being used as a decoder, clone
802 * the MFX session inside it to create a new one */
803 {
804 GstMsdkContext *parent_context, *msdk_context;
805
806 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT " with "
807 "joined session", thiz->context);
808 parent_context = thiz->context;
809 msdk_context = gst_msdk_context_new_with_parent (parent_context);
810
811 if (!msdk_context) {
812 GST_ERROR_OBJECT (thiz, "Failed to create a context with parent context "
813 "as %" GST_PTR_FORMAT, parent_context);
814 return FALSE;
815 }
816
817 thiz->context = msdk_context;
818 gst_msdk_context_add_shared_async_depth (thiz->context,
819 gst_msdk_context_get_shared_async_depth (parent_context));
820 gst_object_unref (parent_context);
821 }
822
823 return TRUE;
824 }
825
826 static gboolean
gst_msdkdec_start(GstVideoDecoder * decoder)827 gst_msdkdec_start (GstVideoDecoder * decoder)
828 {
829 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
830
831 if (!gst_msdkdec_context_prepare (thiz)) {
832 if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
833 thiz->hardware, GST_MSDK_JOB_DECODER))
834 return FALSE;
835 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
836 thiz->context);
837 }
838
839 /* Save the current context in a separate field so that we know whether it
840 * has changed between calls to _start() */
841 gst_object_replace ((GstObject **) & thiz->old_context,
842 (GstObject *) thiz->context);
843
844 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
845
846 return TRUE;
847 }
848
849 static gboolean
gst_msdkdec_close(GstVideoDecoder * decoder)850 gst_msdkdec_close (GstVideoDecoder * decoder)
851 {
852 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
853
854 gst_clear_object (&thiz->context);
855
856 return TRUE;
857 }
858
859 static gboolean
gst_msdkdec_stop(GstVideoDecoder * decoder)860 gst_msdkdec_stop (GstVideoDecoder * decoder)
861 {
862 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
863
864 gst_msdkdec_flush (decoder);
865
866 if (thiz->input_state) {
867 gst_video_codec_state_unref (thiz->input_state);
868 thiz->input_state = NULL;
869 }
870 if (thiz->pool) {
871 gst_object_unref (thiz->pool);
872 thiz->pool = NULL;
873 }
874 gst_video_info_init (&thiz->non_msdk_pool_info);
875
876 gst_msdkdec_close_decoder (thiz, TRUE);
877 return TRUE;
878 }
879
880 static gboolean
gst_msdkdec_set_format(GstVideoDecoder * decoder,GstVideoCodecState * state)881 gst_msdkdec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
882 {
883 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
884
885 if (thiz->input_state) {
886 /* mark for re-negotiation if display resolution or any other video info
887 * changes like framerate. */
888 if (!gst_video_info_is_equal (&thiz->input_state->info, &state->info)) {
889 GST_INFO_OBJECT (thiz, "Schedule renegotiation as video info changed");
890 thiz->do_renego = TRUE;
891 }
892 gst_video_codec_state_unref (thiz->input_state);
893 }
894 thiz->input_state = gst_video_codec_state_ref (state);
895
896 /* we don't set output state here to avoid caching of mismatched
897 * video information if there is dynamic resolution change in the stream.
898 * All negotiation code is consolidated in gst_msdkdec_negotiate() and
899 * this will be invoked from handle_frame() */
900
901 gst_msdkdec_set_latency (thiz);
902 return TRUE;
903 }
904
905 static void
release_msdk_surfaces(GstMsdkDec * thiz)906 release_msdk_surfaces (GstMsdkDec * thiz)
907 {
908 GList *l;
909 MsdkSurface *surface;
910 gint locked = 0;
911 gst_msdkdec_free_unlocked_msdk_surfaces (thiz);
912
913 for (l = thiz->locked_msdk_surfaces; l; l = l->next) {
914 surface = (MsdkSurface *) l->data;
915 unmap_frame (thiz, surface);
916 free_surface (surface);
917 locked++;
918 }
919 if (locked)
920 GST_ERROR_OBJECT (thiz, "msdk still locked %d surfaces", locked);
921 g_list_free (thiz->locked_msdk_surfaces);
922 thiz->locked_msdk_surfaces = NULL;
923 }
924
925 /* This will get invoked in the following situations:
926 * 1: beginning of the stream, which requires initialization (== complete reset)
927 * 2: upstream notified a resolution change and set do_renego to TRUE.
928 * new resolution may or may not requires full reset
929 * 3: upstream failed to notify the resolution change but
930 * msdk detected the change (eg: vp9 stream in ivf elementary form
931 * with varying resolution frames).
932 *
933 * for any input configuration change, we deal with notification
934 * from upstream and also use msdk APIs to handle the parameter initialization
935 * efficiently
936 */
937 static gboolean
gst_msdkdec_negotiate(GstMsdkDec * thiz,gboolean hard_reset)938 gst_msdkdec_negotiate (GstMsdkDec * thiz, gboolean hard_reset)
939 {
940 GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
941 GST_DEBUG_OBJECT (thiz,
942 "Start Negotiating caps, pool and Init the msdk decdoer subsystem");
943
944 if (hard_reset) {
945 /* Retrieve any pending frames and push them downstream */
946 if (gst_msdkdec_drain (GST_VIDEO_DECODER (thiz)) != GST_FLOW_OK)
947 goto error_drain;
948
949 /* This will initiate the allocation query which will help to flush
950 * all the pending buffers in the pipeline so that we can stop
951 * the active bufferpool and safely invoke gst_msdk_frame_free() */
952 if (thiz->initialized) {
953 GstCaps *caps = gst_pad_get_current_caps (decoder->srcpad);
954 GstQuery *query = NULL;
955 if (caps) {
956 query = gst_query_new_allocation (caps, FALSE);
957 gst_pad_peer_query (decoder->srcpad, query);
958 gst_query_unref (query);
959 gst_caps_unref (caps);
960 }
961 }
962
963 /* De-initialize the decoder if it is already active */
964 /* Do not reset the mfxVideoParam since it already
965 * has the required parameters for new session decode */
966 gst_msdkdec_close_decoder (thiz, FALSE);
967
968 /* request for pool re-negotiation by setting do_realloc */
969 thiz->do_realloc = TRUE;
970 }
971
972 /* At this point all pending frames (if there are any) are pushed downstream
973 * and we are ready to negotiate the output caps */
974 if (!gst_msdkdec_set_src_caps (thiz, hard_reset))
975 return FALSE;
976
977 /* this will initiate the allocation query, we create the
978 * bufferpool in decide_allocation in order to account
979 * for the downstream min_buffer requirement
980 * Required initializations for MediaSDK operations
981 * will all be initialized from decide_allocation after considering
982 * some of the downstream requirements */
983 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (thiz)))
984 goto error_negotiate;
985
986 thiz->do_renego = FALSE;
987 thiz->do_realloc = FALSE;
988
989 return TRUE;
990
991 error_drain:
992 GST_ERROR_OBJECT (thiz, "Failed to Drain the queued decoded frames");
993 return FALSE;
994
995 error_negotiate:
996 GST_ERROR_OBJECT (thiz, "Failed to re-negotiate");
997 return FALSE;
998 }
999
1000 static inline gboolean
find_msdk_surface(GstMsdkDec * thiz,MsdkDecTask * task,mfxFrameSurface1 * out_surface)1001 find_msdk_surface (GstMsdkDec * thiz, MsdkDecTask * task,
1002 mfxFrameSurface1 * out_surface)
1003 {
1004 GList *l;
1005 task->surface = NULL;
1006 if (!out_surface)
1007 return TRUE;
1008 l = g_list_find_custom (thiz->locked_msdk_surfaces, out_surface,
1009 _find_msdk_surface);
1010 if (!l) {
1011 GST_ERROR_OBJECT (thiz, "msdk return an invalid surface %p", out_surface);
1012 return FALSE;
1013 }
1014 task->surface = (MsdkSurface *) l->data;
1015 thiz->locked_msdk_surfaces =
1016 g_list_delete_link (thiz->locked_msdk_surfaces, l);
1017 return TRUE;
1018 }
1019
1020 static void
gst_msdkdec_error_report(GstMsdkDec * thiz)1021 gst_msdkdec_error_report (GstMsdkDec * thiz)
1022 {
1023 if (!thiz->report_error)
1024 return;
1025
1026 #if (MFX_VERSION >= 1025)
1027 else {
1028 if (thiz->error_report.ErrorTypes & MFX_ERROR_SPS)
1029 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1030 ("[Error] SPS Error detected!"), (NULL));
1031
1032 if (thiz->error_report.ErrorTypes & MFX_ERROR_PPS)
1033 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1034 ("[Error] PPS Error detected!"), (NULL));
1035
1036 if (thiz->error_report.ErrorTypes & MFX_ERROR_SLICEHEADER)
1037 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1038 ("[Error] SliceHeader Error detected!"), (NULL));
1039
1040 if (thiz->error_report.ErrorTypes & MFX_ERROR_FRAME_GAP)
1041 GST_ELEMENT_WARNING (thiz, STREAM, DECODE,
1042 ("[Error] Frame Gap Error detected!"), (NULL));
1043 }
1044 #endif
1045 }
1046
1047 static GstFlowReturn
gst_msdkdec_handle_frame(GstVideoDecoder * decoder,GstVideoCodecFrame * frame)1048 gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
1049 {
1050 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1051 GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
1052 GstFlowReturn flow;
1053 GstBuffer *buffer, *input_buffer = NULL;
1054 GstVideoInfo alloc_info;
1055 MsdkDecTask *task = NULL;
1056 mfxBitstream bitstream;
1057 MsdkSurface *surface = NULL;
1058 mfxFrameSurface1 *out_surface = NULL;
1059 mfxSession session;
1060 mfxStatus status;
1061 GstMapInfo map_info;
1062 guint i, retry_err_incompatible = 0;
1063 gsize data_size;
1064 gboolean hard_reset = FALSE;
1065 GstClockTime pts = GST_CLOCK_TIME_NONE;
1066
1067 /* configure the subclass in order to fill the CodecID field of
1068 * mfxVideoParam and also to load the PluginID for some of the
1069 * codecs which is mandatory to invoke the
1070 * MFXVideoDECODE_DecodeHeader API.
1071 *
1072 * For non packetized formats (currently only vc1), there
1073 * could be headers received as codec_data which are not available
1074 * instream and in that case subclass implementation will
1075 * push it to the internal adapter. We invoke the subclass configure
1076 * well early to make sure the codec_data received has been correctly
1077 * pushed to the adapter by the subclasses before doing
1078 * the DecodeHeader() later on
1079 */
1080 if (!thiz->initialized || thiz->do_renego) {
1081 /* Clear the internal adapter in re-negotiation for non-packetized
1082 * formats */
1083 if (!gst_video_decoder_get_packetized (decoder))
1084 gst_adapter_clear (thiz->adapter);
1085
1086 if (!klass->configure || !klass->configure (thiz)) {
1087 flow = GST_FLOW_OK;
1088 goto error;
1089 }
1090 }
1091
1092 /* Current frame-codec could be pushed and released before this
1093 * function ends -- because msdkdec pushes the oldest frame,
1094 * according its PTS, and it could be this very same frame-codec
1095 * among others pending frame-codecs.
1096 *
1097 * Instead of copying the input data into the mfxBitstream, let's
1098 * keep an extra reference to frame-codec's input buffer */
1099 input_buffer = gst_buffer_ref (frame->input_buffer);
1100 if (!gst_buffer_map (input_buffer, &map_info, GST_MAP_READ)) {
1101 gst_buffer_unref (input_buffer);
1102 return GST_FLOW_ERROR;
1103 }
1104
1105 memset (&bitstream, 0, sizeof (bitstream));
1106
1107 /* Add extended buffers */
1108 if (thiz->num_bs_extra_params) {
1109 bitstream.NumExtParam = thiz->num_bs_extra_params;
1110 bitstream.ExtParam = thiz->bs_extra_params;
1111 }
1112
1113 if (gst_video_decoder_get_packetized (decoder)) {
1114 /* Packetized stream: we prefer to have a parser as a connected upstream
1115 * element to the decoder */
1116 pts = frame->pts;
1117 bitstream.Data = map_info.data;
1118 bitstream.DataLength = map_info.size;
1119 bitstream.MaxLength = map_info.size;
1120 bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
1121
1122 /*
1123 * MFX_BITSTREAM_COMPLETE_FRAME was removed since commit df59db9, however
1124 * some customers still use DecodedOrder (deprecated in msdk-2017 version)
1125 * for low-latency streaming of non-b-frame encoded streams, which needs to
1126 * output the frame at once, so add it back for this case
1127 */
1128 if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
1129 bitstream.DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME;
1130 } else {
1131 /* Non packetized streams: eg: vc1 advanced profile with per buffer bdu */
1132 gst_adapter_push (thiz->adapter, gst_buffer_ref (input_buffer));
1133 data_size = gst_adapter_available (thiz->adapter);
1134
1135 bitstream.Data = (mfxU8 *) gst_adapter_map (thiz->adapter, data_size);
1136 bitstream.DataLength = (mfxU32) data_size;
1137 bitstream.MaxLength = bitstream.DataLength;
1138 bitstream.TimeStamp = GST_TO_MFX_TIME (pts);
1139 }
1140 GST_DEBUG_OBJECT (thiz,
1141 "mfxBitStream=> DataLength:%d DataOffset:%d MaxLength:%d "
1142 "PTS: %" GST_TIME_FORMAT " MFX TimeStamp %" G_GUINT64_FORMAT,
1143 bitstream.DataLength, bitstream.DataOffset, bitstream.MaxLength,
1144 GST_TIME_ARGS (pts), (guint64) bitstream.TimeStamp);
1145
1146 session = gst_msdk_context_get_session (thiz->context);
1147
1148 if (!thiz->initialized || thiz->do_renego) {
1149
1150 /* gstreamer caps will not provide all the necessary parameters
1151 * required for optimal decode configuration. For example: the required number
1152 * of surfaces to be allocated can be calculated based on H264 SEI header
1153 * and this information can't be retrieved from the negotiated caps.
1154 * So instead of introducing a codecparser dependency to parse the headers
1155 * inside msdk plugin, we simply use the mfx APIs to extract header information */
1156 #if (MFX_VERSION >= 1025)
1157 if (thiz->report_error)
1158 thiz->error_report.ErrorTypes = 0;
1159 #endif
1160
1161 status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1162 GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1163 gst_msdkdec_error_report (thiz);
1164
1165 if (status == MFX_ERR_MORE_DATA) {
1166 flow = GST_FLOW_OK;
1167 goto done;
1168 }
1169
1170 if (!klass->post_configure (thiz)) {
1171 flow = GST_FLOW_ERROR;
1172 goto error;
1173 }
1174
1175 if (!thiz->initialized)
1176 hard_reset = TRUE;
1177 else {
1178 GstVideoCodecState *output_state =
1179 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1180 if (output_state) {
1181 if (output_state->allocation_caps) {
1182 gst_video_info_from_caps (&alloc_info, output_state->allocation_caps);
1183
1184 /* Check whether we need complete reset for dynamic resolution change */
1185 if (thiz->param.mfx.FrameInfo.Width >
1186 GST_VIDEO_INFO_WIDTH (&alloc_info)
1187 || thiz->param.mfx.FrameInfo.Height >
1188 GST_VIDEO_INFO_HEIGHT (&alloc_info))
1189 hard_reset = TRUE;
1190 }
1191 gst_video_codec_state_unref (output_state);
1192 }
1193
1194 }
1195
1196 /* if subclass requested for the force reset */
1197 if (thiz->force_reset_on_res_change)
1198 hard_reset = TRUE;
1199
1200 if (!gst_msdkdec_negotiate (thiz, hard_reset)) {
1201 GST_ELEMENT_ERROR (thiz, CORE, NEGOTIATION,
1202 ("Could not negotiate the stream"), (NULL));
1203 flow = GST_FLOW_ERROR;
1204 goto error;
1205 }
1206 }
1207
1208 /* gst_msdkdec_handle_frame owns one ref on input argument |frame|. At this
1209 * point this frame is not used so just unref it right away.
1210 * gst_msdkdec_finish_task is fetching the frames itself. */
1211 gst_video_codec_frame_unref (frame);
1212 frame = NULL;
1213 for (;;) {
1214 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1215 flow = gst_msdkdec_finish_task (thiz, task);
1216 if (flow != GST_FLOW_OK) {
1217 if (flow == GST_FLOW_ERROR)
1218 GST_ERROR_OBJECT (thiz, "Failed to finish a task");
1219 goto error;
1220 }
1221 if (!surface) {
1222 flow = allocate_output_buffer (thiz, &buffer);
1223 if (flow == GST_FLOW_CUSTOM_SUCCESS) {
1224 flow = GST_FLOW_OK;
1225 break;
1226 } else if (flow != GST_FLOW_OK)
1227 goto error;
1228 surface = get_surface (thiz, buffer);
1229 if (!surface) {
1230 /* Can't get a surface for some reason; finish tasks, then see if
1231 a surface becomes available. */
1232 for (i = 0; i < thiz->tasks->len - 1; i++) {
1233 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1234 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1235 flow = gst_msdkdec_finish_task (thiz, task);
1236 if (flow != GST_FLOW_OK)
1237 goto error;
1238 surface = get_surface (thiz, buffer);
1239 if (surface)
1240 break;
1241 }
1242 if (!surface) {
1243 GST_ERROR_OBJECT (thiz, "Couldn't get a surface");
1244 flow = GST_FLOW_ERROR;
1245 goto error;
1246 }
1247 }
1248 }
1249 #if (MFX_VERSION >= 1025)
1250 if (thiz->report_error)
1251 thiz->error_report.ErrorTypes = 0;
1252 #endif
1253
1254 status =
1255 MFXVideoDECODE_DecodeFrameAsync (session, &bitstream, surface->surface,
1256 &out_surface, &task->sync_point);
1257
1258 if (!find_msdk_surface (thiz, task, out_surface)) {
1259 flow = GST_FLOW_ERROR;
1260 goto done;
1261 }
1262
1263 GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1264 gst_msdkdec_error_report (thiz);
1265
1266 /* media-sdk requires complete reset since the surface is inadequate
1267 * for further decoding */
1268 if (status == MFX_ERR_INCOMPATIBLE_VIDEO_PARAM &&
1269 retry_err_incompatible++ < 1) {
1270 /* MFX_ERR_INCOMPATIBLE_VIDEO_PARAM means the current mfx surface is not
1271 * suitable for the current frame. Call MFXVideoDECODE_DecodeHeader to get
1272 * the current frame size, then do memory re-allocation, otherwise
1273 * MFXVideoDECODE_DecodeFrameAsync will still fail on next call */
1274 #if (MFX_VERSION >= 1025)
1275 if (thiz->report_error)
1276 thiz->error_report.ErrorTypes = 0;
1277 #endif
1278 status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
1279 GST_DEBUG_OBJECT (decoder, "DecodeHeader => %d", status);
1280 gst_msdkdec_error_report (thiz);
1281
1282 if (status == MFX_ERR_MORE_DATA) {
1283 flow = GST_FLOW_OK;
1284 goto done;
1285 }
1286
1287 /* Requires memory re-allocation, do a hard reset */
1288 if (!gst_msdkdec_negotiate (thiz, TRUE))
1289 goto error;
1290
1291 /* The current surface is freed when doing a hard reset; a new surface is
1292 * required for the new resolution */
1293 surface = NULL;
1294 continue;
1295 }
1296
1297 retry_err_incompatible = 0;
1298
1299 if (G_LIKELY (status == MFX_ERR_NONE)
1300 || (status == MFX_WRN_VIDEO_PARAM_CHANGED)) {
1301 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1302
1303 if (surface->surface->Data.Locked > 0)
1304 surface = NULL;
1305
1306 if (bitstream.DataLength == 0) {
1307 flow = GST_FLOW_OK;
1308
1309 /* Don't release it if the current surface is in use */
1310 if (surface && task->surface->surface == surface->surface)
1311 surface = NULL;
1312
1313 break;
1314 }
1315 } else if (status == MFX_ERR_MORE_DATA) {
1316 if (task->surface) {
1317 task->decode_only = TRUE;
1318 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1319 }
1320
1321 if (surface->surface->Data.Locked > 0)
1322 surface = NULL;
1323 flow = GST_VIDEO_DECODER_FLOW_NEED_DATA;
1324 break;
1325 } else if (status == MFX_ERR_MORE_SURFACE) {
1326 surface = NULL;
1327 continue;
1328 } else if (status == MFX_WRN_DEVICE_BUSY) {
1329 /* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
1330 g_usleep (1000);
1331
1332 if (surface->surface->Data.Locked > 0)
1333 surface = NULL;
1334
1335 /* If the current surface is still busy, we should do sync operation,
1336 * then try to decode again
1337 */
1338 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1339 } else if (status < MFX_ERR_NONE) {
1340 GST_ERROR_OBJECT (thiz, "DecodeFrameAsync failed (%s)",
1341 msdk_status_to_string (status));
1342 flow = GST_FLOW_ERROR;
1343 break;
1344 }
1345 }
1346
1347 if (!gst_video_decoder_get_packetized (decoder)) {
1348 /* flush out the data which has already been consumed by msdk */
1349 gst_adapter_flush (thiz->adapter, bitstream.DataOffset);
1350 }
1351
1352 /*
1353 * DecodedOrder was deprecated in msdk-2017 version, but some
1354 * customers still using this for low-latency streaming of non-b-frame
1355 * encoded streams, which needs to output the frame at once
1356 */
1357 if (thiz->param.mfx.DecodedOrder == GST_MSDKDEC_OUTPUT_ORDER_DECODE)
1358 gst_msdkdec_finish_task (thiz, task);
1359
1360 done:
1361 gst_buffer_unmap (input_buffer, &map_info);
1362 gst_buffer_unref (input_buffer);
1363 return flow;
1364
1365 error:
1366 if (input_buffer) {
1367 gst_buffer_unmap (input_buffer, &map_info);
1368 gst_buffer_unref (input_buffer);
1369 }
1370 if (frame)
1371 gst_video_decoder_drop_frame (decoder, frame);
1372
1373 return flow;
1374 }
1375
1376 static GstFlowReturn
gst_msdkdec_parse(GstVideoDecoder * decoder,GstVideoCodecFrame * frame,GstAdapter * adapter,gboolean at_eos)1377 gst_msdkdec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame,
1378 GstAdapter * adapter, gboolean at_eos)
1379 {
1380 gsize size;
1381 GstFlowReturn ret;
1382 GstBuffer *buffer;
1383 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1384
1385 /* Don't parse the input buffer indeed, it will invoke
1386 * gst_msdkdec_handle_frame to handle the input buffer */
1387 size = gst_adapter_available (adapter);
1388 gst_video_decoder_add_to_frame (decoder, size);
1389 ret = gst_video_decoder_have_frame (decoder);
1390 size = gst_adapter_available (thiz->adapter);
1391
1392 if (size) {
1393 /* The base class will set up a new frame for parsing as
1394 * soon as there is valid data in the buffer */
1395 buffer = gst_adapter_get_buffer (thiz->adapter, size);
1396 gst_adapter_flush (thiz->adapter, size);
1397 gst_adapter_push (adapter, buffer);
1398 }
1399
1400 return ret;
1401 }
1402
1403 static GstBufferPool *
gst_msdkdec_create_buffer_pool(GstMsdkDec * thiz,GstVideoInfo * info,guint num_buffers)1404 gst_msdkdec_create_buffer_pool (GstMsdkDec * thiz, GstVideoInfo * info,
1405 guint num_buffers)
1406 {
1407 GstBufferPool *pool = NULL;
1408 GstStructure *config;
1409 GstAllocator *allocator = NULL;
1410 GstVideoAlignment align;
1411 GstCaps *caps = NULL;
1412 GstAllocationParams params = { 0, 31, 0, 0, };
1413 mfxFrameAllocResponse *alloc_resp = NULL;
1414
1415 g_return_val_if_fail (info, NULL);
1416 g_return_val_if_fail (GST_VIDEO_INFO_WIDTH (info)
1417 && GST_VIDEO_INFO_HEIGHT (info), NULL);
1418
1419 alloc_resp = &thiz->alloc_resp;
1420
1421 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
1422 if (!pool)
1423 goto error_no_pool;
1424
1425 caps = gst_video_info_to_caps (info);
1426
1427 /* allocators should use the same width/height/stride/height_alignment of
1428 * negotiated output caps, which is what we configure in msdk_allocator */
1429 if (thiz->use_dmabuf)
1430 allocator = gst_msdk_dmabuf_allocator_new (thiz->context, info, alloc_resp);
1431 else if (thiz->use_video_memory)
1432 allocator = gst_msdk_video_allocator_new (thiz->context, info, alloc_resp);
1433 else
1434 allocator = gst_msdk_system_allocator_new (info);
1435
1436 if (!allocator) {
1437 gst_caps_unref (caps);
1438 goto error_no_allocator;
1439 }
1440
1441 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1442 /* we need register all bufffers when we create the msdk context, so the buffer pool is not resize able */
1443 gst_buffer_pool_config_set_params (config, caps,
1444 GST_VIDEO_INFO_SIZE (info), num_buffers, num_buffers);
1445 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1446 gst_buffer_pool_config_add_option (config,
1447 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1448 gst_caps_unref (caps);
1449
1450 if (thiz->use_video_memory) {
1451 gst_buffer_pool_config_add_option (config,
1452 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
1453 if (thiz->use_dmabuf)
1454 gst_buffer_pool_config_add_option (config,
1455 GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
1456 }
1457
1458
1459 gst_buffer_pool_config_set_video_alignment (config, &align);
1460 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
1461 gst_object_unref (allocator);
1462
1463 if (!gst_buffer_pool_set_config (pool, config))
1464 goto error_pool_config;
1465
1466 return pool;
1467
1468 error_no_pool:
1469 {
1470 GST_INFO_OBJECT (thiz, "failed to create bufferpool");
1471 return NULL;
1472 }
1473 error_no_allocator:
1474 {
1475 GST_INFO_OBJECT (thiz, "failed to create allocator");
1476 gst_object_unref (pool);
1477 return NULL;
1478 }
1479 error_pool_config:
1480 {
1481 GST_INFO_OBJECT (thiz, "failed to set config");
1482 gst_object_unref (pool);
1483 gst_object_unref (allocator);
1484 return NULL;
1485 }
1486 }
1487
1488 static gboolean
gst_msdkdec_decide_allocation(GstVideoDecoder * decoder,GstQuery * query)1489 gst_msdkdec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
1490 {
1491 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1492 GstBufferPool *pool = NULL;
1493 GstStructure *pool_config = NULL;
1494 GstCaps *pool_caps /*, *negotiated_caps */ ;
1495 guint size, min_buffers, max_buffers;
1496
1497 if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
1498 query))
1499 return FALSE;
1500
1501 /* Get the buffer pool config decided on by the base class. The base
1502 class ensures that there will always be at least a 0th pool in
1503 the query. */
1504 gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
1505 pool_config = gst_buffer_pool_get_config (pool);
1506
1507 /* Get the caps of pool and increase the min and max buffers by async_depth.
1508 * We will always have that number of decode operations in-flight */
1509 gst_buffer_pool_config_get_params (pool_config, &pool_caps, &size,
1510 &min_buffers, &max_buffers);
1511 min_buffers += thiz->async_depth;
1512 if (max_buffers)
1513 max_buffers += thiz->async_depth;
1514
1515 /* increase the min_buffers by 1 for smooth display in render pipeline */
1516 min_buffers += 1;
1517
1518 /* this will get updated with msdk requirement */
1519 thiz->min_prealloc_buffers = min_buffers;
1520
1521 if (_gst_caps_has_feature (pool_caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
1522 GST_INFO_OBJECT (decoder, "This MSDK decoder uses DMABuf memory");
1523 thiz->use_video_memory = thiz->use_dmabuf = TRUE;
1524 }
1525
1526 /* Initialize MSDK decoder before new bufferpool tries to alloc each buffer,
1527 * which requires information about frame allocation.
1528 * No effect if already initialized.
1529 */
1530 if (!gst_msdkdec_init_decoder (thiz))
1531 return FALSE;
1532
1533 /* get the updated min_buffers, which account for the msdk requirement as well */
1534 min_buffers = thiz->min_prealloc_buffers;
1535
1536 /* Decoder always use its own pool. So we create a pool if msdk APIs
1537 * previously requested for allocation (do_realloc = TRUE) */
1538 if (thiz->do_realloc || !thiz->pool) {
1539 GstVideoCodecState *output_state =
1540 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1541 gst_clear_object (&thiz->pool);
1542 GST_INFO_OBJECT (decoder, "create new MSDK bufferpool");
1543 thiz->pool =
1544 gst_msdkdec_create_buffer_pool (thiz, &output_state->info, min_buffers);
1545 gst_video_codec_state_unref (output_state);
1546 if (!thiz->pool) {
1547 GST_ERROR_OBJECT (decoder, "failed to create new pool");
1548 goto failed_to_create_pool;
1549 }
1550 }
1551
1552 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)
1553 && gst_buffer_pool_has_option (pool,
1554 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) {
1555 GstStructure *config;
1556 GstAllocator *allocator;
1557
1558 /* If downstream supports video meta and video alignment,
1559 * we can replace with our own msdk bufferpool and use it
1560 */
1561 /* Remove downstream's pool */
1562 gst_structure_free (pool_config);
1563 gst_object_unref (pool);
1564
1565 pool = gst_object_ref (thiz->pool);
1566
1567 /* Set the allocator of new msdk bufferpool */
1568 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
1569
1570 if (gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
1571 gst_query_set_nth_allocation_param (query, 0, allocator, NULL);
1572 gst_structure_free (config);
1573 } else {
1574 /* Unfortunately, downstream doesn't have videometa or alignment support,
1575 * we keep msdk pool as a side-pool that will be decoded into and
1576 * then copied from.
1577 */
1578 GstVideoCodecState *output_state = NULL;
1579
1580 GST_INFO_OBJECT (decoder, "Keep MSDK bufferpool as a side-pool");
1581
1582 /* Update params to downstream's pool */
1583 gst_buffer_pool_config_set_params (pool_config, pool_caps, size,
1584 min_buffers, max_buffers);
1585 if (!gst_buffer_pool_set_config (pool, pool_config))
1586 goto error_set_config;
1587 gst_video_info_from_caps (&thiz->non_msdk_pool_info, pool_caps);
1588
1589 /* update width and height with actual negotiated values */
1590 output_state =
1591 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (thiz));
1592 GST_VIDEO_INFO_WIDTH (&thiz->non_msdk_pool_info) =
1593 GST_VIDEO_INFO_WIDTH (&output_state->info);
1594 GST_VIDEO_INFO_HEIGHT (&thiz->non_msdk_pool_info) =
1595 GST_VIDEO_INFO_HEIGHT (&output_state->info);
1596 gst_video_codec_state_unref (output_state);
1597 }
1598
1599 gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
1600 max_buffers);
1601
1602 if (pool)
1603 gst_object_unref (pool);
1604
1605
1606 return TRUE;
1607
1608 failed_to_create_pool:
1609 GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1610 if (pool)
1611 gst_object_unref (pool);
1612 return FALSE;
1613
1614 error_set_config:
1615 GST_ERROR_OBJECT (decoder, "failed to set buffer pool config");
1616 if (pool)
1617 gst_object_unref (pool);
1618 return FALSE;
1619 }
1620
1621 static GstFlowReturn
gst_msdkdec_drain(GstVideoDecoder * decoder)1622 gst_msdkdec_drain (GstVideoDecoder * decoder)
1623 {
1624 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1625 GstFlowReturn flow;
1626 GstBuffer *buffer;
1627 MsdkDecTask *task;
1628 MsdkSurface *surface = NULL;
1629 mfxFrameSurface1 *out_surface;
1630 mfxSession session;
1631 mfxStatus status;
1632 guint i;
1633
1634 if (!thiz->initialized)
1635 return GST_FLOW_OK;
1636 session = gst_msdk_context_get_session (thiz->context);
1637
1638 for (;;) {
1639 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1640 if ((flow = gst_msdkdec_finish_task (thiz, task)) != GST_FLOW_OK) {
1641 if (flow != GST_FLOW_FLUSHING)
1642 GST_WARNING_OBJECT (decoder,
1643 "failed to finish the task %p, but keep draining for the remaining frames",
1644 task);
1645 }
1646
1647 if (!surface) {
1648 flow = allocate_output_buffer (thiz, &buffer);
1649 if (flow != GST_FLOW_OK)
1650 return flow;
1651 surface = get_surface (thiz, buffer);
1652 if (!surface)
1653 return GST_FLOW_ERROR;
1654 }
1655 #if (MFX_VERSION >= 1025)
1656 if (thiz->report_error)
1657 thiz->error_report.ErrorTypes = 0;
1658 #endif
1659
1660 status =
1661 MFXVideoDECODE_DecodeFrameAsync (session, NULL, surface->surface,
1662 &out_surface, &task->sync_point);
1663
1664 if (!find_msdk_surface (thiz, task, out_surface)) {
1665 return GST_FLOW_ERROR;
1666 }
1667
1668 GST_DEBUG_OBJECT (decoder, "DecodeFrameAsync => %d", status);
1669 gst_msdkdec_error_report (thiz);
1670
1671 if (G_LIKELY (status == MFX_ERR_NONE)) {
1672 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1673 surface = NULL;
1674 } else if (status == MFX_WRN_VIDEO_PARAM_CHANGED) {
1675 continue;
1676 } else if (status == MFX_WRN_DEVICE_BUSY) {
1677 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
1678 g_usleep (1000);
1679
1680 /* If the current surface is still busy, we should do sync operation,
1681 * then try to decode again
1682 */
1683 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1684 } else if (status == MFX_ERR_MORE_DATA) {
1685 break;
1686 } else if (status == MFX_ERR_MORE_SURFACE) {
1687 surface = NULL;
1688 continue;
1689 } else if (status < MFX_ERR_NONE)
1690 return GST_FLOW_ERROR;
1691 }
1692
1693 for (i = 0; i < thiz->tasks->len; i++) {
1694 task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
1695 gst_msdkdec_finish_task (thiz, task);
1696 thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
1697 }
1698
1699 return GST_FLOW_OK;
1700 }
1701
1702 static gboolean
gst_msdkdec_flush(GstVideoDecoder * decoder)1703 gst_msdkdec_flush (GstVideoDecoder * decoder)
1704 {
1705 GstMsdkDec *thiz = GST_MSDKDEC (decoder);
1706 GstFlowReturn ret;
1707
1708 ret = gst_msdkdec_drain (GST_VIDEO_DECODER_CAST (thiz));
1709
1710 return ret == GST_FLOW_OK;
1711 }
1712
1713 static GstFlowReturn
gst_msdkdec_finish(GstVideoDecoder * decoder)1714 gst_msdkdec_finish (GstVideoDecoder * decoder)
1715 {
1716 return gst_msdkdec_drain (decoder);
1717 }
1718
1719 static void
gst_msdkdec_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1720 gst_msdkdec_set_property (GObject * object, guint prop_id, const GValue * value,
1721 GParamSpec * pspec)
1722 {
1723 GstMsdkDec *thiz = GST_MSDKDEC (object);
1724 GstState state;
1725
1726 GST_OBJECT_LOCK (thiz);
1727
1728 state = GST_STATE (thiz);
1729 if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1730 !(pspec->flags & GST_PARAM_MUTABLE_PLAYING))
1731 goto wrong_state;
1732
1733 switch (prop_id) {
1734 case GST_MSDKDEC_PROP_HARDWARE:
1735 thiz->hardware = g_value_get_boolean (value);
1736 break;
1737 case GST_MSDKDEC_PROP_ASYNC_DEPTH:
1738 thiz->async_depth = g_value_get_uint (value);
1739 break;
1740 default:
1741 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1742 break;
1743 }
1744 GST_OBJECT_UNLOCK (thiz);
1745 return;
1746
1747 /* ERROR */
1748 wrong_state:
1749 {
1750 GST_WARNING_OBJECT (thiz, "setting property in wrong state");
1751 GST_OBJECT_UNLOCK (thiz);
1752 }
1753 }
1754
1755 static void
gst_msdkdec_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1756 gst_msdkdec_get_property (GObject * object, guint prop_id, GValue * value,
1757 GParamSpec * pspec)
1758 {
1759 GstMsdkDec *thiz = GST_MSDKDEC (object);
1760
1761 GST_OBJECT_LOCK (thiz);
1762 switch (prop_id) {
1763 case GST_MSDKDEC_PROP_HARDWARE:
1764 g_value_set_boolean (value, thiz->hardware);
1765 break;
1766 case GST_MSDKDEC_PROP_ASYNC_DEPTH:
1767 g_value_set_uint (value, thiz->async_depth);
1768 break;
1769 default:
1770 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1771 break;
1772 }
1773 GST_OBJECT_UNLOCK (thiz);
1774 }
1775
1776 static void
gst_msdkdec_dispose(GObject * object)1777 gst_msdkdec_dispose (GObject * object)
1778 {
1779 GstMsdkDec *thiz = GST_MSDKDEC (object);
1780
1781 g_clear_object (&thiz->adapter);
1782 gst_clear_object (&thiz->context);
1783 gst_clear_object (&thiz->old_context);
1784
1785 G_OBJECT_CLASS (parent_class)->dispose (object);
1786 }
1787
1788 static void
gst_msdkdec_finalize(GObject * object)1789 gst_msdkdec_finalize (GObject * object)
1790 {
1791 GstMsdkDec *thiz = GST_MSDKDEC (object);
1792
1793 g_array_unref (thiz->tasks);
1794 thiz->tasks = NULL;
1795
1796 release_msdk_surfaces (thiz);
1797
1798 G_OBJECT_CLASS (parent_class)->finalize (object);
1799 }
1800
1801 static gboolean
gst_msdkdec_post_configure(GstMsdkDec * decoder)1802 gst_msdkdec_post_configure (GstMsdkDec * decoder)
1803 {
1804 /* Do nothing */
1805 return TRUE;
1806 }
1807
1808 static gboolean
gst_msdkdec_preinit_decoder(GstMsdkDec * decoder)1809 gst_msdkdec_preinit_decoder (GstMsdkDec * decoder)
1810 {
1811 decoder->param.mfx.FrameInfo.Width =
1812 GST_ROUND_UP_16 (decoder->param.mfx.FrameInfo.Width);
1813 decoder->param.mfx.FrameInfo.Height =
1814 GST_ROUND_UP_32 (decoder->param.mfx.FrameInfo.Height);
1815
1816 decoder->param.mfx.FrameInfo.PicStruct =
1817 decoder->param.mfx.FrameInfo.PicStruct ? decoder->param.mfx.
1818 FrameInfo.PicStruct : MFX_PICSTRUCT_PROGRESSIVE;
1819
1820 return TRUE;
1821 }
1822
1823 static gboolean
gst_msdkdec_postinit_decoder(GstMsdkDec * decoder)1824 gst_msdkdec_postinit_decoder (GstMsdkDec * decoder)
1825 {
1826 /* Do nothing */
1827 return TRUE;
1828 }
1829
1830 static gboolean
gst_msdkdec_transform_meta(GstVideoDecoder * decoder,GstVideoCodecFrame * frame,GstMeta * meta)1831 gst_msdkdec_transform_meta (GstVideoDecoder * decoder,
1832 GstVideoCodecFrame * frame, GstMeta * meta)
1833 {
1834 const GstMetaInfo *info = meta->info;
1835
1836 if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (decoder, frame,
1837 meta))
1838 return TRUE;
1839
1840 if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta"))
1841 return TRUE;
1842
1843 return FALSE;
1844 }
1845
1846 static void
gst_msdkdec_class_init(GstMsdkDecClass * klass)1847 gst_msdkdec_class_init (GstMsdkDecClass * klass)
1848 {
1849 GObjectClass *gobject_class;
1850 GstElementClass *element_class;
1851 GstVideoDecoderClass *decoder_class;
1852
1853 gobject_class = G_OBJECT_CLASS (klass);
1854 element_class = GST_ELEMENT_CLASS (klass);
1855 decoder_class = GST_VIDEO_DECODER_CLASS (klass);
1856
1857 gobject_class->set_property = gst_msdkdec_set_property;
1858 gobject_class->get_property = gst_msdkdec_get_property;
1859 gobject_class->dispose = gst_msdkdec_dispose;
1860 gobject_class->finalize = gst_msdkdec_finalize;
1861
1862 element_class->set_context = gst_msdkdec_set_context;
1863
1864 decoder_class->close = GST_DEBUG_FUNCPTR (gst_msdkdec_close);
1865 decoder_class->start = GST_DEBUG_FUNCPTR (gst_msdkdec_start);
1866 decoder_class->stop = GST_DEBUG_FUNCPTR (gst_msdkdec_stop);
1867 decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_msdkdec_set_format);
1868 decoder_class->finish = GST_DEBUG_FUNCPTR (gst_msdkdec_finish);
1869 decoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_msdkdec_handle_frame);
1870 decoder_class->parse = GST_DEBUG_FUNCPTR (gst_msdkdec_parse);
1871 decoder_class->decide_allocation =
1872 GST_DEBUG_FUNCPTR (gst_msdkdec_decide_allocation);
1873 decoder_class->flush = GST_DEBUG_FUNCPTR (gst_msdkdec_flush);
1874 decoder_class->drain = GST_DEBUG_FUNCPTR (gst_msdkdec_drain);
1875 decoder_class->transform_meta =
1876 GST_DEBUG_FUNCPTR (gst_msdkdec_transform_meta);
1877
1878 klass->post_configure = GST_DEBUG_FUNCPTR (gst_msdkdec_post_configure);
1879 klass->preinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_preinit_decoder);
1880 klass->postinit_decoder = GST_DEBUG_FUNCPTR (gst_msdkdec_postinit_decoder);
1881
1882 g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_HARDWARE,
1883 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware decoders",
1884 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1885
1886 g_object_class_install_property (gobject_class, GST_MSDKDEC_PROP_ASYNC_DEPTH,
1887 g_param_spec_uint ("async-depth", "Async Depth",
1888 "Depth of asynchronous pipeline",
1889 1, 20, PROP_ASYNC_DEPTH_DEFAULT,
1890 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1891
1892 gst_element_class_add_static_pad_template (element_class, &src_factory);
1893 }
1894
1895 static void
gst_msdkdec_init(GstMsdkDec * thiz)1896 gst_msdkdec_init (GstMsdkDec * thiz)
1897 {
1898 gst_video_info_init (&thiz->non_msdk_pool_info);
1899 thiz->tasks = g_array_new (FALSE, TRUE, sizeof (MsdkDecTask));
1900 thiz->hardware = PROP_HARDWARE_DEFAULT;
1901 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1902 thiz->do_renego = TRUE;
1903 thiz->do_realloc = TRUE;
1904 thiz->force_reset_on_res_change = TRUE;
1905 thiz->report_error = FALSE;
1906 thiz->adapter = gst_adapter_new ();
1907 thiz->input_state = NULL;
1908 thiz->pool = NULL;
1909 thiz->context = NULL;
1910 }
1911