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