|
48 | 48 | #include "config_win32.h"
|
49 | 49 | #endif // defined HAVE_CONFIG_H
|
50 | 50 |
|
51 |
| -#include "hwaccel_vaapi.h" |
52 |
| - |
53 |
| -#include "debug.h" |
54 |
| - |
55 |
| -#include "hwaccel_libav_common.h" |
56 | 51 | #include <libavcodec/version.h>
|
| 52 | +#include <libavutil/pixdesc.h> |
57 | 53 | #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 74, 100)
|
58 | 54 | #include <libavcodec/vaapi.h>
|
59 | 55 | #endif
|
60 | 56 | #include <libavutil/hwcontext_vaapi.h>
|
61 | 57 |
|
| 58 | +#include "debug.h" |
| 59 | +#include "hwaccel_libav_common.h" |
| 60 | +#include "hwaccel_vaapi.h" |
| 61 | +#include "libavcodec/lavc_common.h" |
| 62 | + |
62 | 63 | #define DEFAULT_SURFACES 20
|
| 64 | +#define MOD_NAME "[vaapi] " |
63 | 65 |
|
64 | 66 | struct vaapi_ctx {
|
65 | 67 | AVBufferRef *device_ref;
|
@@ -196,6 +198,84 @@ static int vaapi_create_context(struct vaapi_ctx *ctx,
|
196 | 198 | }
|
197 | 199 | #endif //LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 74, 100)
|
198 | 200 |
|
| 201 | +/** |
| 202 | + * Returns first SW format from valid_sw_formats. This is usually |
| 203 | + * AV_PIX_FMT_YUV420P or AV_PIX_FMT_NV12. |
| 204 | + * |
| 205 | + * The code borrows heavily from mpv |
| 206 | + * <https://github.com/mpv-player/mpv/blob/master/video/out/hwdec/hwdec_vaapi.c> |
| 207 | + * namely from function try_format_config(). |
| 208 | + */ |
| 209 | +static enum AVPixelFormat |
| 210 | +get_sw_format(VADisplay display, AVBufferRef *device_ref, |
| 211 | + enum AVPixelFormat fallback_fmt) |
| 212 | +{ |
| 213 | + enum AVPixelFormat ret = AV_PIX_FMT_NONE; |
| 214 | + AVVAAPIHWConfig *hwconfig = NULL; |
| 215 | + VAConfigID config_id = 0; |
| 216 | + AVHWFramesConstraints *fc = NULL; |
| 217 | + |
| 218 | + VAStatus status = vaCreateConfig( |
| 219 | + display, VAProfileNone, VAEntrypointVideoProc, NULL, 0, &config_id); |
| 220 | + if (status != VA_STATUS_SUCCESS) { |
| 221 | + MSG(ERROR, "cannot create config\n"); |
| 222 | + goto fail; |
| 223 | + } |
| 224 | + fc = av_hwdevice_get_hwframe_constraints(device_ref, hwconfig); |
| 225 | + if (!fc) { |
| 226 | + MSG(ERROR, "failed to retrieve libavutil frame constraints\n"); |
| 227 | + goto fail; |
| 228 | + } |
| 229 | + |
| 230 | + /* |
| 231 | + * We need a hwframe_ctx to be able to get the valid formats, but to |
| 232 | + * initialise it, we need a format, so we get the first format from the |
| 233 | + * hwconfig. We don't care about the other formats in the config because |
| 234 | + * the transfer formats list will already include them. |
| 235 | + */ |
| 236 | + AVBufferRef *fref = NULL; |
| 237 | + fref = av_hwframe_ctx_alloc(device_ref); |
| 238 | + if (!fref) { |
| 239 | + MSG(ERROR, "failed to alloc libavutil frame context\n"); |
| 240 | + goto fail; |
| 241 | + } |
| 242 | + AVHWFramesContext *fctx = (void *) fref->data; |
| 243 | + enum { |
| 244 | + INIT_SIZE = 128, ///< just some valid size |
| 245 | + }; |
| 246 | + fctx->format = AV_PIX_FMT_VAAPI; |
| 247 | + fctx->sw_format = fc->valid_sw_formats[0]; |
| 248 | + fctx->width = INIT_SIZE; |
| 249 | + fctx->height = INIT_SIZE; |
| 250 | + if (av_hwframe_ctx_init(fref) < 0) { |
| 251 | + MSG(ERROR, "failed to init libavutil frame context\n"); |
| 252 | + goto fail; |
| 253 | + } |
| 254 | + |
| 255 | + enum AVPixelFormat *fmts = NULL; |
| 256 | + int rc = av_hwframe_transfer_get_formats( |
| 257 | + fref, AV_HWFRAME_TRANSFER_DIRECTION_FROM, &fmts, 0); |
| 258 | + if (rc) { |
| 259 | + MSG(ERROR, "failed to get libavutil frame context supported " |
| 260 | + "formats\n"); |
| 261 | + goto fail; |
| 262 | + } |
| 263 | + MSG(DEBUG, "Available HW layouts: %s\n", get_avpixfmts_names(fmts)); |
| 264 | + ret = fmts[0]; |
| 265 | + |
| 266 | +fail: |
| 267 | + av_hwframe_constraints_free(&fc); |
| 268 | + av_buffer_unref(&fref); |
| 269 | + if (ret == AV_PIX_FMT_NONE) { |
| 270 | + MSG(WARNING, "Using fallback HW frames layout: %s\n", |
| 271 | + av_get_pix_fmt_name(ret)); |
| 272 | + ret = fallback_fmt; |
| 273 | + } |
| 274 | + MSG(VERBOSE, "Selected HW frames layout: %s\n", |
| 275 | + av_get_pix_fmt_name(ret)); |
| 276 | + return ret; |
| 277 | +} |
| 278 | + |
199 | 279 | int vaapi_init(struct AVCodecContext *s,
|
200 | 280 | struct hw_accel_state *state,
|
201 | 281 | codec_t out_codec)
|
@@ -224,11 +304,13 @@ int vaapi_init(struct AVCodecContext *s,
|
224 | 304 | if (s->active_thread_type & FF_THREAD_FRAME)
|
225 | 305 | decode_surfaces += s->thread_count;
|
226 | 306 |
|
| 307 | + const enum AVPixelFormat sw_format = get_sw_format( |
| 308 | + ctx->device_vaapi_ctx->display, ctx->device_ref, s->sw_pix_fmt); |
227 | 309 | ret = create_hw_frame_ctx(ctx->device_ref,
|
228 | 310 | s->coded_width,
|
229 | 311 | s->coded_height,
|
230 | 312 | AV_PIX_FMT_VAAPI,
|
231 |
| - s->sw_pix_fmt, |
| 313 | + sw_format, |
232 | 314 | decode_surfaces,
|
233 | 315 | &ctx->hw_frames_ctx);
|
234 | 316 | if(ret < 0)
|
|
0 commit comments