1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2016, Oblong Industries, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "msdk.h"
33 #include "gstmsdkvideomemory.h"
34 #include "gstmsdksystemmemory.h"
35
36 GST_DEBUG_CATEGORY_EXTERN (gst_msdk_debug);
37 #define GST_CAT_DEFAULT gst_msdk_debug
38
39 #define INVALID_INDEX ((guint) -1)
40 #define GST_MSDK_ALIGNMENT_PADDING(num,padding) ((padding) - ((num) & ((padding) - 1)))
41
42 struct map
43 {
44 GstVideoFormat format;
45 mfxU16 mfx_chroma_format;
46 mfxU32 mfx_fourcc;
47 };
48
49 #define GST_VIDEO_INFO_TO_MFX_MAP(FORMAT, CHROMA, FOURCC) \
50 { GST_VIDEO_FORMAT_##FORMAT, MFX_CHROMAFORMAT_##CHROMA, MFX_FOURCC_##FOURCC }
51
52 static const struct map gst_msdk_video_format_to_mfx_map[] = {
53 GST_VIDEO_INFO_TO_MFX_MAP (NV12, YUV420, NV12),
54 GST_VIDEO_INFO_TO_MFX_MAP (YV12, YUV420, YV12),
55 GST_VIDEO_INFO_TO_MFX_MAP (I420, YUV420, YV12),
56 GST_VIDEO_INFO_TO_MFX_MAP (P010_10LE, YUV420, P010),
57 GST_VIDEO_INFO_TO_MFX_MAP (YUY2, YUV422, YUY2),
58 GST_VIDEO_INFO_TO_MFX_MAP (UYVY, YUV422, UYVY),
59 GST_VIDEO_INFO_TO_MFX_MAP (BGRA, YUV444, RGB4),
60 GST_VIDEO_INFO_TO_MFX_MAP (BGRx, YUV444, RGB4),
61 #if (MFX_VERSION >= 1028)
62 GST_VIDEO_INFO_TO_MFX_MAP (RGB16, YUV444, RGB565),
63 #endif
64 GST_VIDEO_INFO_TO_MFX_MAP (VUYA, YUV444, AYUV),
65 GST_VIDEO_INFO_TO_MFX_MAP (BGR10A2_LE, YUV444, A2RGB10),
66 {0, 0, 0}
67 };
68
69 const gchar *
msdk_status_to_string(mfxStatus status)70 msdk_status_to_string (mfxStatus status)
71 {
72 switch (status) {
73 /* no error */
74 case MFX_ERR_NONE:
75 return "no error";
76 /* reserved for unexpected errors */
77 case MFX_ERR_UNKNOWN:
78 return "unknown error";
79 /* error codes <0 */
80 case MFX_ERR_NULL_PTR:
81 return "null pointer";
82 case MFX_ERR_UNSUPPORTED:
83 return "undeveloped feature";
84 case MFX_ERR_MEMORY_ALLOC:
85 return "failed to allocate memory";
86 case MFX_ERR_NOT_ENOUGH_BUFFER:
87 return "insufficient buffer at input/output";
88 case MFX_ERR_INVALID_HANDLE:
89 return "invalid handle";
90 case MFX_ERR_LOCK_MEMORY:
91 return "failed to lock the memory block";
92 case MFX_ERR_NOT_INITIALIZED:
93 return "member function called before initialization";
94 case MFX_ERR_NOT_FOUND:
95 return "the specified object is not found";
96 case MFX_ERR_MORE_DATA:
97 return "expect more data at input";
98 case MFX_ERR_MORE_SURFACE:
99 return "expect more surface at output";
100 case MFX_ERR_ABORTED:
101 return "operation aborted";
102 case MFX_ERR_DEVICE_LOST:
103 return "lose the HW acceleration device";
104 case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
105 return "incompatible video parameters";
106 case MFX_ERR_INVALID_VIDEO_PARAM:
107 return "invalid video parameters";
108 case MFX_ERR_UNDEFINED_BEHAVIOR:
109 return "undefined behavior";
110 case MFX_ERR_DEVICE_FAILED:
111 return "device operation failure";
112 case MFX_ERR_MORE_BITSTREAM:
113 return "expect more bitstream buffers at output";
114 case MFX_ERR_INCOMPATIBLE_AUDIO_PARAM:
115 return "incompatible audio parameters";
116 case MFX_ERR_INVALID_AUDIO_PARAM:
117 return "invalid audio parameters";
118 /* warnings >0 */
119 case MFX_WRN_IN_EXECUTION:
120 return "the previous asynchronous operation is in execution";
121 case MFX_WRN_DEVICE_BUSY:
122 return "the HW acceleration device is busy";
123 case MFX_WRN_VIDEO_PARAM_CHANGED:
124 return "the video parameters are changed during decoding";
125 case MFX_WRN_PARTIAL_ACCELERATION:
126 return "SW is used";
127 case MFX_WRN_INCOMPATIBLE_VIDEO_PARAM:
128 return "incompatible video parameters";
129 case MFX_WRN_VALUE_NOT_CHANGED:
130 return "the value is saturated based on its valid range";
131 case MFX_WRN_OUT_OF_RANGE:
132 return "the value is out of valid range";
133 case MFX_WRN_FILTER_SKIPPED:
134 return "one of requested filters has been skipped";
135 case MFX_WRN_INCOMPATIBLE_AUDIO_PARAM:
136 return "incompatible audio parameters";
137 default:
138 break;
139 }
140 return "undefiend error";
141 }
142
143 void
msdk_close_session(mfxSession session)144 msdk_close_session (mfxSession session)
145 {
146 mfxStatus status;
147
148 if (!session)
149 return;
150
151 status = MFXClose (session);
152 if (status != MFX_ERR_NONE)
153 GST_ERROR ("Close failed (%s)", msdk_status_to_string (status));
154 }
155
156 mfxSession
msdk_open_session(mfxIMPL impl)157 msdk_open_session (mfxIMPL impl)
158 {
159 mfxSession session = NULL;
160 mfxVersion version = { {1, 1}
161 };
162 mfxIMPL implementation;
163 mfxStatus status;
164
165 static const gchar *implementation_names[] = {
166 "AUTO", "SOFTWARE", "HARDWARE", "AUTO_ANY", "HARDWARE_ANY", "HARDWARE2",
167 "HARDWARE3", "HARDWARE4", "RUNTIME"
168 };
169
170 status = MFXInit (impl, &version, &session);
171 if (status != MFX_ERR_NONE) {
172 GST_ERROR ("Intel Media SDK not available (%s)",
173 msdk_status_to_string (status));
174 goto failed;
175 }
176
177 status = MFXQueryIMPL (session, &implementation);
178 if (status != MFX_ERR_NONE) {
179 GST_ERROR ("Query implementation failed (%s)",
180 msdk_status_to_string (status));
181 goto failed;
182 }
183
184 status = MFXQueryVersion (session, &version);
185 if (status != MFX_ERR_NONE) {
186 GST_ERROR ("Query version failed (%s)", msdk_status_to_string (status));
187 goto failed;
188 }
189
190 GST_INFO ("MSDK implementation: 0x%04x (%s)", implementation,
191 implementation_names[MFX_IMPL_BASETYPE (implementation)]);
192 GST_INFO ("MSDK version: %d.%d", version.Major, version.Minor);
193
194 return session;
195
196 failed:
197 msdk_close_session (session);
198 return NULL;
199 }
200
201 gboolean
msdk_is_available(void)202 msdk_is_available (void)
203 {
204 mfxSession session = msdk_open_session (MFX_IMPL_AUTO_ANY);
205 if (!session) {
206 return FALSE;
207 }
208
209 msdk_close_session (session);
210 return TRUE;
211 }
212
213 void
gst_msdk_set_video_alignment(GstVideoInfo * info,GstVideoAlignment * alignment)214 gst_msdk_set_video_alignment (GstVideoInfo * info,
215 GstVideoAlignment * alignment)
216 {
217 guint i, width, height;
218
219 width = GST_VIDEO_INFO_WIDTH (info);
220 height = GST_VIDEO_INFO_HEIGHT (info);
221
222 gst_video_alignment_reset (alignment);
223 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++)
224 alignment->stride_align[i] = 15; /* 16-byte alignment */
225
226 if (width & 15)
227 alignment->padding_right = GST_MSDK_ALIGNMENT_PADDING (width, 16);
228 if (height & 31)
229 alignment->padding_bottom = GST_MSDK_ALIGNMENT_PADDING (height, 32);
230 }
231
232 static const struct map *
_map_lookup_format(GstVideoFormat format)233 _map_lookup_format (GstVideoFormat format)
234 {
235 const struct map *m = gst_msdk_video_format_to_mfx_map;
236
237 for (; m->format != 0; m++) {
238 if (m->format == format)
239 return m;
240 }
241 return NULL;
242 }
243
244 gint
gst_msdk_get_mfx_chroma_from_format(GstVideoFormat format)245 gst_msdk_get_mfx_chroma_from_format (GstVideoFormat format)
246 {
247 const struct map *const m = _map_lookup_format (format);
248
249 return m ? m->mfx_chroma_format : -1;
250 }
251
252 gint
gst_msdk_get_mfx_fourcc_from_format(GstVideoFormat format)253 gst_msdk_get_mfx_fourcc_from_format (GstVideoFormat format)
254 {
255 const struct map *const m = _map_lookup_format (format);
256
257 return m ? m->mfx_fourcc : -1;
258 }
259
260 void
gst_msdk_set_mfx_frame_info_from_video_info(mfxFrameInfo * mfx_info,GstVideoInfo * info)261 gst_msdk_set_mfx_frame_info_from_video_info (mfxFrameInfo * mfx_info,
262 GstVideoInfo * info)
263 {
264 g_return_if_fail (info && mfx_info);
265
266 mfx_info->Width = GST_ROUND_UP_16 (GST_VIDEO_INFO_WIDTH (info));
267 mfx_info->Height = GST_ROUND_UP_32 (GST_VIDEO_INFO_HEIGHT (info));
268 mfx_info->CropW = GST_VIDEO_INFO_WIDTH (info);
269 mfx_info->CropH = GST_VIDEO_INFO_HEIGHT (info);
270 mfx_info->FrameRateExtN = GST_VIDEO_INFO_FPS_N (info);
271 mfx_info->FrameRateExtD = GST_VIDEO_INFO_FPS_D (info);
272 mfx_info->AspectRatioW = GST_VIDEO_INFO_PAR_N (info);
273 mfx_info->AspectRatioH = GST_VIDEO_INFO_PAR_D (info);
274 mfx_info->PicStruct =
275 !GST_VIDEO_INFO_IS_INTERLACED (info) ? MFX_PICSTRUCT_PROGRESSIVE :
276 MFX_PICSTRUCT_UNKNOWN;
277 mfx_info->FourCC =
278 gst_msdk_get_mfx_fourcc_from_format (GST_VIDEO_INFO_FORMAT (info));
279 mfx_info->ChromaFormat =
280 gst_msdk_get_mfx_chroma_from_format (GST_VIDEO_INFO_FORMAT (info));
281
282 if (mfx_info->FourCC == MFX_FOURCC_P010) {
283 mfx_info->BitDepthLuma = 10;
284 mfx_info->BitDepthChroma = 10;
285 mfx_info->Shift = 1;
286 }
287
288 return;
289 }
290
291 gboolean
gst_msdk_is_msdk_buffer(GstBuffer * buf)292 gst_msdk_is_msdk_buffer (GstBuffer * buf)
293 {
294 GstAllocator *allocator;
295 GstMemory *mem = gst_buffer_peek_memory (buf, 0);
296
297 allocator = GST_MEMORY_CAST (mem)->allocator;
298
299 if (allocator && (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator) ||
300 GST_IS_MSDK_SYSTEM_ALLOCATOR (allocator) ||
301 GST_IS_MSDK_DMABUF_ALLOCATOR (allocator)))
302 return TRUE;
303 else
304 return FALSE;
305 }
306
307 mfxFrameSurface1 *
gst_msdk_get_surface_from_buffer(GstBuffer * buf)308 gst_msdk_get_surface_from_buffer (GstBuffer * buf)
309 {
310 GstAllocator *allocator;
311 GstMemory *mem = gst_buffer_peek_memory (buf, 0);
312
313 allocator = GST_MEMORY_CAST (mem)->allocator;
314
315 if (GST_IS_MSDK_VIDEO_ALLOCATOR (allocator))
316 return GST_MSDK_VIDEO_MEMORY_CAST (mem)->surface;
317 else if (GST_IS_MSDK_SYSTEM_ALLOCATOR (allocator))
318 return GST_MSDK_SYSTEM_MEMORY_CAST (mem)->surface;
319 else if (GST_IS_MSDK_DMABUF_ALLOCATOR (allocator)) {
320 return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
321 g_quark_from_static_string ("GstMsdkBufferSurface"));
322 }
323
324 return NULL;
325 }
326
327 GstVideoFormat
gst_msdk_get_video_format_from_mfx_fourcc(mfxU32 fourcc)328 gst_msdk_get_video_format_from_mfx_fourcc (mfxU32 fourcc)
329 {
330 const struct map *m = gst_msdk_video_format_to_mfx_map;
331
332 for (; m->mfx_fourcc != 0; m++) {
333 if (m->mfx_fourcc == fourcc)
334 return m->format;
335 }
336
337 return GST_VIDEO_FORMAT_UNKNOWN;
338 }
339