2 * This file is part of FFmpeg.
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <mfx/mfxvideo.h>
22 #include "libavutil/dict.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/opt.h"
25 #include "libavcodec/qsv.h"
29 typedef struct QSVContext
{
34 mfxExtOpaqueSurfaceAlloc opaque_alloc
;
35 AVBufferRef
*opaque_surfaces_buf
;
37 uint8_t *surface_used
;
38 mfxFrameSurface1
**surface_ptrs
;
41 mfxExtBuffer
*ext_buffers
[1];
44 static void buffer_release(void *opaque
, uint8_t *data
)
46 *(uint8_t*)opaque
= 0;
49 static int qsv_get_buffer(AVCodecContext
*s
, AVFrame
*frame
, int flags
)
51 InputStream
*ist
= s
->opaque
;
52 QSVContext
*qsv
= ist
->hwaccel_ctx
;
55 for (i
= 0; i
< qsv
->nb_surfaces
; i
++) {
56 if (qsv
->surface_used
[i
])
59 frame
->buf
[0] = av_buffer_create((uint8_t*)qsv
->surface_ptrs
[i
], sizeof(*qsv
->surface_ptrs
[i
]),
60 buffer_release
, &qsv
->surface_used
[i
], 0);
62 return AVERROR(ENOMEM
);
63 frame
->data
[3] = (uint8_t*)qsv
->surface_ptrs
[i
];
64 qsv
->surface_used
[i
] = 1;
68 return AVERROR(ENOMEM
);
71 static int init_opaque_surf(QSVContext
*qsv
)
73 AVQSVContext
*hwctx_enc
= qsv
->ost
->enc_ctx
->hwaccel_context
;
74 mfxFrameSurface1
*surfaces
;
77 qsv
->nb_surfaces
= hwctx_enc
->nb_opaque_surfaces
;
79 qsv
->opaque_surfaces_buf
= av_buffer_ref(hwctx_enc
->opaque_surfaces
);
80 qsv
->surface_ptrs
= av_mallocz_array(qsv
->nb_surfaces
, sizeof(*qsv
->surface_ptrs
));
81 qsv
->surface_used
= av_mallocz_array(qsv
->nb_surfaces
, sizeof(*qsv
->surface_used
));
82 if (!qsv
->opaque_surfaces_buf
|| !qsv
->surface_ptrs
|| !qsv
->surface_used
)
83 return AVERROR(ENOMEM
);
85 surfaces
= (mfxFrameSurface1
*)qsv
->opaque_surfaces_buf
->data
;
86 for (i
= 0; i
< qsv
->nb_surfaces
; i
++)
87 qsv
->surface_ptrs
[i
] = surfaces
+ i
;
89 qsv
->opaque_alloc
.Out
.Surfaces
= qsv
->surface_ptrs
;
90 qsv
->opaque_alloc
.Out
.NumSurface
= qsv
->nb_surfaces
;
91 qsv
->opaque_alloc
.Out
.Type
= hwctx_enc
->opaque_alloc_type
;
93 qsv
->opaque_alloc
.Header
.BufferId
= MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION
;
94 qsv
->opaque_alloc
.Header
.BufferSz
= sizeof(qsv
->opaque_alloc
);
95 qsv
->ext_buffers
[0] = (mfxExtBuffer
*)&qsv
->opaque_alloc
;
100 static void qsv_uninit(AVCodecContext
*s
)
102 InputStream
*ist
= s
->opaque
;
103 QSVContext
*qsv
= ist
->hwaccel_ctx
;
105 av_freep(&qsv
->ost
->enc_ctx
->hwaccel_context
);
106 av_freep(&s
->hwaccel_context
);
108 av_buffer_unref(&qsv
->opaque_surfaces_buf
);
109 av_freep(&qsv
->surface_used
);
110 av_freep(&qsv
->surface_ptrs
);
115 int qsv_init(AVCodecContext
*s
)
117 InputStream
*ist
= s
->opaque
;
118 QSVContext
*qsv
= ist
->hwaccel_ctx
;
119 AVQSVContext
*hwctx_dec
;
123 av_log(NULL
, AV_LOG_ERROR
, "QSV transcoding is not initialized. "
124 "-hwaccel qsv should only be used for one-to-one QSV transcoding "
125 "with no filters.\n");
129 ret
= init_opaque_surf(qsv
);
133 hwctx_dec
= av_qsv_alloc_context();
135 return AVERROR(ENOMEM
);
137 hwctx_dec
->session
= qsv
->session
;
138 hwctx_dec
->iopattern
= MFX_IOPATTERN_OUT_OPAQUE_MEMORY
;
139 hwctx_dec
->ext_buffers
= qsv
->ext_buffers
;
140 hwctx_dec
->nb_ext_buffers
= FF_ARRAY_ELEMS(qsv
->ext_buffers
);
142 av_freep(&s
->hwaccel_context
);
143 s
->hwaccel_context
= hwctx_dec
;
145 ist
->hwaccel_get_buffer
= qsv_get_buffer
;
146 ist
->hwaccel_uninit
= qsv_uninit
;
151 static mfxIMPL
choose_implementation(const InputStream
*ist
)
153 static const struct {
157 { "auto", MFX_IMPL_AUTO
},
158 { "sw", MFX_IMPL_SOFTWARE
},
159 { "hw", MFX_IMPL_HARDWARE
},
160 { "auto_any", MFX_IMPL_AUTO_ANY
},
161 { "hw_any", MFX_IMPL_HARDWARE_ANY
},
162 { "hw2", MFX_IMPL_HARDWARE2
},
163 { "hw3", MFX_IMPL_HARDWARE3
},
164 { "hw4", MFX_IMPL_HARDWARE4
},
167 mfxIMPL impl
= MFX_IMPL_AUTO_ANY
;
170 if (ist
->hwaccel_device
) {
171 for (i
= 0; i
< FF_ARRAY_ELEMS(impl_map
); i
++)
172 if (!strcmp(ist
->hwaccel_device
, impl_map
[i
].name
)) {
173 impl
= impl_map
[i
].impl
;
176 if (i
== FF_ARRAY_ELEMS(impl_map
))
177 impl
= strtol(ist
->hwaccel_device
, NULL
, 0);
183 int qsv_transcode_init(OutputStream
*ost
)
186 const enum AVPixelFormat
*pix_fmt
;
188 AVDictionaryEntry
*e
;
194 QSVContext
*qsv
= NULL
;
195 AVQSVContext
*hwctx
= NULL
;
197 mfxVersion ver
= { { 3, 1 } };
199 /* check if the encoder supports QSV */
200 if (!ost
->enc
->pix_fmts
)
202 for (pix_fmt
= ost
->enc
->pix_fmts
; *pix_fmt
!= AV_PIX_FMT_NONE
; pix_fmt
++)
203 if (*pix_fmt
== AV_PIX_FMT_QSV
)
205 if (*pix_fmt
== AV_PIX_FMT_NONE
)
208 if (strcmp(ost
->avfilter
, "null") || ost
->source_index
< 0)
211 /* check if the decoder supports QSV and the output only goes to this stream */
212 ist
= input_streams
[ost
->source_index
];
213 if (ist
->hwaccel_id
!= HWACCEL_QSV
|| !ist
->dec
|| !ist
->dec
->pix_fmts
)
215 for (pix_fmt
= ist
->dec
->pix_fmts
; *pix_fmt
!= AV_PIX_FMT_NONE
; pix_fmt
++)
216 if (*pix_fmt
== AV_PIX_FMT_QSV
)
218 if (*pix_fmt
== AV_PIX_FMT_NONE
)
221 for (i
= 0; i
< nb_output_streams
; i
++)
222 if (output_streams
[i
] != ost
&&
223 output_streams
[i
]->source_index
== ost
->source_index
)
226 av_log(NULL
, AV_LOG_VERBOSE
, "Setting up QSV transcoding\n");
228 qsv
= av_mallocz(sizeof(*qsv
));
229 hwctx
= av_qsv_alloc_context();
233 impl
= choose_implementation(ist
);
235 err
= MFXInit(impl
, &ver
, &qsv
->session
);
236 if (err
!= MFX_ERR_NONE
) {
237 av_log(NULL
, AV_LOG_ERROR
, "Error initializing an MFX session: %d\n", err
);
241 e
= av_dict_get(ost
->encoder_opts
, "flags", NULL
, 0);
242 opt
= av_opt_find(ost
->enc_ctx
, "flags", NULL
, 0, 0);
244 av_opt_eval_flags(ost
->enc_ctx
, opt
, e
->value
, &flags
);
248 hwctx
->session
= qsv
->session
;
249 hwctx
->iopattern
= MFX_IOPATTERN_IN_OPAQUE_MEMORY
;
250 hwctx
->opaque_alloc
= 1;
251 hwctx
->nb_opaque_surfaces
= 16;
253 ost
->hwaccel_ctx
= qsv
;
254 ost
->enc_ctx
->hwaccel_context
= hwctx
;
255 ost
->enc_ctx
->pix_fmt
= AV_PIX_FMT_QSV
;
257 ist
->hwaccel_ctx
= qsv
;
258 ist
->dec_ctx
->pix_fmt
= AV_PIX_FMT_QSV
;
259 ist
->resample_pix_fmt
= AV_PIX_FMT_QSV
;
266 return AVERROR_UNKNOWN
;