FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
qsv.c
Go to the documentation of this file.
1 /*
2  * Intel MediaSDK QSV encoder/decoder shared code
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <mfx/mfxvideo.h>
22 #include <mfx/mfxplugin.h>
23 
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "libavutil/avstring.h"
28 #include "libavutil/error.h"
29 
30 #include "avcodec.h"
31 #include "qsv_internal.h"
32 
34 {
35  switch (codec_id) {
36  case AV_CODEC_ID_H264:
37  return MFX_CODEC_AVC;
38 #if QSV_VERSION_ATLEAST(1, 8)
39  case AV_CODEC_ID_HEVC:
40  return MFX_CODEC_HEVC;
41 #endif
44  return MFX_CODEC_MPEG2;
45  case AV_CODEC_ID_VC1:
46  return MFX_CODEC_VC1;
47  default:
48  break;
49  }
50 
51  return AVERROR(ENOSYS);
52 }
53 
54 int ff_qsv_error(int mfx_err)
55 {
56  switch (mfx_err) {
57  case MFX_ERR_NONE:
58  return 0;
59  case MFX_ERR_MEMORY_ALLOC:
60  case MFX_ERR_NOT_ENOUGH_BUFFER:
61  return AVERROR(ENOMEM);
62  case MFX_ERR_INVALID_HANDLE:
63  return AVERROR(EINVAL);
64  case MFX_ERR_DEVICE_FAILED:
65  case MFX_ERR_DEVICE_LOST:
66  case MFX_ERR_LOCK_MEMORY:
67  return AVERROR(EIO);
68  case MFX_ERR_NULL_PTR:
69  case MFX_ERR_UNDEFINED_BEHAVIOR:
70  case MFX_ERR_NOT_INITIALIZED:
71  return AVERROR_BUG;
72  case MFX_ERR_UNSUPPORTED:
73  case MFX_ERR_NOT_FOUND:
74  return AVERROR(ENOSYS);
75  case MFX_ERR_MORE_DATA:
76  case MFX_ERR_MORE_SURFACE:
77  case MFX_ERR_MORE_BITSTREAM:
78  return AVERROR(EAGAIN);
79  case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
80  case MFX_ERR_INVALID_VIDEO_PARAM:
81  return AVERROR(EINVAL);
82  case MFX_ERR_ABORTED:
83  case MFX_ERR_UNKNOWN:
84  default:
85  return AVERROR_UNKNOWN;
86  }
87 }
89 {
90  // this code is only required for Linux. It searches for a valid
91  // display handle. First in /dev/dri/renderD then in /dev/dri/card
92 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
93  // VAAPI display handle
94  int ret = 0;
95  VADisplay va_dpy = NULL;
96  VAStatus va_res = VA_STATUS_SUCCESS;
97  int major_version = 0, minor_version = 0;
98  int fd = -1;
99  char adapterpath[256];
100  int adapter_num;
101 
102  qs->fd_display = -1;
103  qs->va_display = NULL;
104 
105  //search for valid graphics device
106  for (adapter_num = 0;adapter_num < 6;adapter_num++) {
107 
108  if (adapter_num<3) {
109  snprintf(adapterpath,sizeof(adapterpath),
110  "/dev/dri/renderD%d", adapter_num+128);
111  } else {
112  snprintf(adapterpath,sizeof(adapterpath),
113  "/dev/dri/card%d", adapter_num-3);
114  }
115 
116  fd = open(adapterpath, O_RDWR);
117  if (fd < 0) {
118  av_log(avctx, AV_LOG_ERROR,
119  "mfx init: %s fd open failed\n", adapterpath);
120  continue;
121  }
122 
123  va_dpy = vaGetDisplayDRM(fd);
124  if (!va_dpy) {
125  av_log(avctx, AV_LOG_ERROR,
126  "mfx init: %s vaGetDisplayDRM failed\n", adapterpath);
127  close(fd);
128  continue;
129  }
130 
131  va_res = vaInitialize(va_dpy, &major_version, &minor_version);
132  if (VA_STATUS_SUCCESS != va_res) {
133  av_log(avctx, AV_LOG_ERROR,
134  "mfx init: %s vaInitialize failed\n", adapterpath);
135  close(fd);
136  fd = -1;
137  continue;
138  } else {
139  av_log(avctx, AV_LOG_VERBOSE,
140  "mfx initialization: %s vaInitialize successful\n",adapterpath);
141  qs->fd_display = fd;
142  qs->va_display = va_dpy;
143  ret = MFXVideoCORE_SetHandle(qs->session,
144  (mfxHandleType)MFX_HANDLE_VA_DISPLAY, (mfxHDL)va_dpy);
145  if (ret < 0) {
146  av_log(avctx, AV_LOG_ERROR,
147  "Error %d during set display handle\n", ret);
148  return ff_qsv_error(ret);
149  }
150  break;
151  }
152  }
153 #endif //AVCODEC_QSV_LINUX_SESSION_HANDLE
154  return 0;
155 }
156 /**
157  * @brief Initialize a MSDK session
158  *
159  * Media SDK is based on sessions, so this is the prerequisite
160  * initialization for HW acceleration. For Windows the session is
161  * complete and ready to use, for Linux a display handle is
162  * required. For releases of Media Server Studio >= 2015 R4 the
163  * render nodes interface is preferred (/dev/dri/renderD).
164  * Using Media Server Studio 2015 R4 or newer is recommended
165  * but the older /dev/dri/card interface is also searched
166  * for broader compatibility.
167  *
168  * @param avctx ffmpeg metadata for this codec context
169  * @param session the MSDK session used
170  */
172  const char *load_plugins)
173 {
174  mfxIMPL impl = MFX_IMPL_AUTO_ANY;
175  mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } };
176 
177  const char *desc;
178  int ret;
179 
180  ret = MFXInit(impl, &ver, &qs->session);
181  if (ret < 0) {
182  av_log(avctx, AV_LOG_ERROR, "Error initializing an internal MFX session\n");
183  return ff_qsv_error(ret);
184  }
185 
186  ret = ff_qsv_set_display_handle(avctx, qs);
187  if (ret < 0)
188  return ret;
189 
190  if (load_plugins && *load_plugins) {
191  while (*load_plugins) {
192  mfxPluginUID uid;
193  int i, err = 0;
194 
195  char *plugin = av_get_token(&load_plugins, ":");
196  if (!plugin)
197  return AVERROR(ENOMEM);
198  if (strlen(plugin) != 2 * sizeof(uid.Data)) {
199  av_log(avctx, AV_LOG_ERROR, "Invalid plugin UID length\n");
200  err = AVERROR(EINVAL);
201  goto load_plugin_fail;
202  }
203 
204  for (i = 0; i < sizeof(uid.Data); i++) {
205  err = sscanf(plugin + 2 * i, "%2hhx", uid.Data + i);
206  if (err != 1) {
207  av_log(avctx, AV_LOG_ERROR, "Invalid plugin UID\n");
208  err = AVERROR(EINVAL);
209  goto load_plugin_fail;
210  }
211 
212  }
213 
214  ret = MFXVideoUSER_Load(qs->session, &uid, 1);
215  if (ret < 0) {
216  av_log(avctx, AV_LOG_ERROR, "Could not load the requested plugin: %s\n",
217  plugin);
218  err = ff_qsv_error(ret);
219  goto load_plugin_fail;
220  }
221 
222  if (*load_plugins)
223  load_plugins++;
224 load_plugin_fail:
225  av_freep(&plugin);
226  if (err < 0)
227  return err;
228  }
229  }
230 
231  MFXQueryIMPL(qs->session, &impl);
232 
233  switch (MFX_IMPL_BASETYPE(impl)) {
234  case MFX_IMPL_SOFTWARE:
235  desc = "software";
236  break;
237  case MFX_IMPL_HARDWARE:
238  case MFX_IMPL_HARDWARE2:
239  case MFX_IMPL_HARDWARE3:
240  case MFX_IMPL_HARDWARE4:
241  desc = "hardware accelerated";
242  break;
243  default:
244  desc = "unknown";
245  }
246 
247  av_log(avctx, AV_LOG_VERBOSE,
248  "Initialized an internal MFX session using %s implementation\n",
249  desc);
250 
251  return 0;
252 }
253 
255 {
256  if (qs->session) {
257  MFXClose(qs->session);
258  qs->session = NULL;
259  }
260 #ifdef AVCODEC_QSV_LINUX_SESSION_HANDLE
261  if (qs->va_display) {
262  vaTerminate(qs->va_display);
263  qs->va_display = NULL;
264  }
265  if (qs->fd_display > 0) {
266  close(qs->fd_display);
267  qs->fd_display = -1;
268  }
269 #endif
270  return 0;
271 }
#define NULL
Definition: coverity.c:32
enum AVCodecID codec_id
Definition: ffmpeg_vaapi.c:149
const char * desc
Definition: nvenc.c:89
UID uid
Definition: mxfenc.c:1820
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
#define av_log(a,...)
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:189
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
error code definitions
#define AVERROR(e)
Definition: error.h:43
int ff_qsv_close_internal_session(QSVSession *qs)
Definition: qsv.c:254
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition: avstring.c:149
#define QSV_VERSION_MINOR
Definition: qsv_internal.h:46
int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id)
Definition: qsv.c:33
preferred ID for MPEG-1/2 video decoding
Definition: avcodec.h:194
int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, const char *load_plugins)
Initialize a MSDK session.
Definition: qsv.c:171
Libavcodec external API header.
main external API structure.
Definition: avcodec.h:1649
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
#define snprintf
Definition: snprintf.h:34
int ff_qsv_error(int mfx_err)
Convert a libmfx error code into a ffmpeg error code.
Definition: qsv.c:54
#define QSV_VERSION_MAJOR
Definition: qsv_internal.h:45
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs)
Definition: qsv.c:88
#define av_freep(p)
mfxSession session
Definition: qsv_internal.h:69