2 * This file is part of Libav.
4 * Libav 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 * Libav 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 Libav; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "hwcontext.h"
24 #include "hwcontext_internal.h"
31 static const HWContextType
*hw_table
[] = {
35 static const AVClass hwdevice_ctx_class
= {
36 .class_name
= "AVHWDeviceContext",
37 .item_name
= av_default_item_name
,
38 .version
= LIBAVUTIL_VERSION_INT
,
41 static void hwdevice_ctx_free(void *opaque
, uint8_t *data
)
43 AVHWDeviceContext
*ctx
= (AVHWDeviceContext
*)data
;
45 /* uninit might still want access the hw context and the user
46 * free() callback might destroy it, so uninit has to be called first */
47 if (ctx
->internal
->hw_type
->device_uninit
)
48 ctx
->internal
->hw_type
->device_uninit(ctx
);
53 av_freep(&ctx
->hwctx
);
54 av_freep(&ctx
->internal
->priv
);
55 av_freep(&ctx
->internal
);
59 AVBufferRef
*av_hwdevice_ctx_alloc(enum AVHWDeviceType type
)
61 AVHWDeviceContext
*ctx
;
63 const HWContextType
*hw_type
= NULL
;
66 for (i
= 0; hw_table
[i
]; i
++) {
67 if (hw_table
[i
]->type
== type
) {
68 hw_type
= hw_table
[i
];
75 ctx
= av_mallocz(sizeof(*ctx
));
79 ctx
->internal
= av_mallocz(sizeof(*ctx
->internal
));
83 if (hw_type
->device_priv_size
) {
84 ctx
->internal
->priv
= av_mallocz(hw_type
->device_priv_size
);
85 if (!ctx
->internal
->priv
)
89 if (hw_type
->device_hwctx_size
) {
90 ctx
->hwctx
= av_mallocz(hw_type
->device_hwctx_size
);
95 buf
= av_buffer_create((uint8_t*)ctx
, sizeof(*ctx
),
96 hwdevice_ctx_free
, NULL
,
97 AV_BUFFER_FLAG_READONLY
);
102 ctx
->av_class
= &hwdevice_ctx_class
;
104 ctx
->internal
->hw_type
= hw_type
;
110 av_freep(&ctx
->internal
->priv
);
111 av_freep(&ctx
->internal
);
112 av_freep(&ctx
->hwctx
);
117 int av_hwdevice_ctx_init(AVBufferRef
*ref
)
119 AVHWDeviceContext
*ctx
= (AVHWDeviceContext
*)ref
->data
;
122 if (ctx
->internal
->hw_type
->device_init
) {
123 ret
= ctx
->internal
->hw_type
->device_init(ctx
);
130 if (ctx
->internal
->hw_type
->device_uninit
)
131 ctx
->internal
->hw_type
->device_uninit(ctx
);
135 static const AVClass hwframe_ctx_class
= {
136 .class_name
= "AVHWFramesContext",
137 .item_name
= av_default_item_name
,
138 .version
= LIBAVUTIL_VERSION_INT
,
141 static void hwframe_ctx_free(void *opaque
, uint8_t *data
)
143 AVHWFramesContext
*ctx
= (AVHWFramesContext
*)data
;
145 if (ctx
->internal
->pool_internal
)
146 av_buffer_pool_uninit(&ctx
->internal
->pool_internal
);
148 if (ctx
->internal
->hw_type
->frames_uninit
)
149 ctx
->internal
->hw_type
->frames_uninit(ctx
);
154 av_buffer_unref(&ctx
->device_ref
);
156 av_freep(&ctx
->hwctx
);
157 av_freep(&ctx
->internal
->priv
);
158 av_freep(&ctx
->internal
);
162 AVBufferRef
*av_hwframe_ctx_alloc(AVBufferRef
*device_ref_in
)
164 AVHWDeviceContext
*device_ctx
= (AVHWDeviceContext
*)device_ref_in
->data
;
165 const HWContextType
*hw_type
= device_ctx
->internal
->hw_type
;
166 AVHWFramesContext
*ctx
;
167 AVBufferRef
*buf
, *device_ref
= NULL
;;
169 ctx
= av_mallocz(sizeof(*ctx
));
173 ctx
->internal
= av_mallocz(sizeof(*ctx
->internal
));
177 if (hw_type
->frames_priv_size
) {
178 ctx
->internal
->priv
= av_mallocz(hw_type
->frames_priv_size
);
179 if (!ctx
->internal
->priv
)
183 if (hw_type
->frames_hwctx_size
) {
184 ctx
->hwctx
= av_mallocz(hw_type
->frames_hwctx_size
);
189 device_ref
= av_buffer_ref(device_ref_in
);
193 buf
= av_buffer_create((uint8_t*)ctx
, sizeof(*ctx
),
194 hwframe_ctx_free
, NULL
,
195 AV_BUFFER_FLAG_READONLY
);
199 ctx
->av_class
= &hwframe_ctx_class
;
200 ctx
->device_ref
= device_ref
;
201 ctx
->device_ctx
= device_ctx
;
202 ctx
->format
= AV_PIX_FMT_NONE
;
204 ctx
->internal
->hw_type
= hw_type
;
210 av_buffer_unref(&device_ref
);
212 av_freep(&ctx
->internal
->priv
);
213 av_freep(&ctx
->internal
);
214 av_freep(&ctx
->hwctx
);
219 static int hwframe_pool_prealloc(AVBufferRef
*ref
)
221 AVHWFramesContext
*ctx
= (AVHWFramesContext
*)ref
->data
;
225 frames
= av_mallocz_array(ctx
->initial_pool_size
, sizeof(*frames
));
227 return AVERROR(ENOMEM
);
229 for (i
= 0; i
< ctx
->initial_pool_size
; i
++) {
230 frames
[i
] = av_frame_alloc();
234 ret
= av_hwframe_get_buffer(ref
, frames
[i
], 0);
240 for (i
= 0; i
< ctx
->initial_pool_size
; i
++)
241 av_frame_free(&frames
[i
]);
247 int av_hwframe_ctx_init(AVBufferRef
*ref
)
249 AVHWFramesContext
*ctx
= (AVHWFramesContext
*)ref
->data
;
250 const enum AVPixelFormat
*pix_fmt
;
253 /* validate the pixel format */
254 for (pix_fmt
= ctx
->internal
->hw_type
->pix_fmts
; *pix_fmt
!= AV_PIX_FMT_NONE
; pix_fmt
++) {
255 if (*pix_fmt
== ctx
->format
)
258 if (*pix_fmt
== AV_PIX_FMT_NONE
) {
259 av_log(ctx
, AV_LOG_ERROR
,
260 "The hardware pixel format '%s' is not supported by the device type '%s'\n",
261 av_get_pix_fmt_name(ctx
->format
), ctx
->internal
->hw_type
->name
);
262 return AVERROR(ENOSYS
);
265 /* validate the dimensions */
266 ret
= av_image_check_size(ctx
->width
, ctx
->height
, 0, ctx
);
270 /* format-specific init */
271 if (ctx
->internal
->hw_type
->frames_init
) {
272 ret
= ctx
->internal
->hw_type
->frames_init(ctx
);
277 if (ctx
->internal
->pool_internal
&& !ctx
->pool
)
278 ctx
->pool
= ctx
->internal
->pool_internal
;
280 /* preallocate the frames in the pool, if requested */
281 if (ctx
->initial_pool_size
> 0) {
282 ret
= hwframe_pool_prealloc(ref
);
289 if (ctx
->internal
->hw_type
->frames_uninit
)
290 ctx
->internal
->hw_type
->frames_uninit(ctx
);
294 int av_hwframe_transfer_get_formats(AVBufferRef
*hwframe_ref
,
295 enum AVHWFrameTransferDirection dir
,
296 enum AVPixelFormat
**formats
, int flags
)
298 AVHWFramesContext
*ctx
= (AVHWFramesContext
*)hwframe_ref
->data
;
300 if (!ctx
->internal
->hw_type
->transfer_get_formats
)
301 return AVERROR(ENOSYS
);
303 return ctx
->internal
->hw_type
->transfer_get_formats(ctx
, dir
, formats
);
306 static int transfer_data_alloc(AVFrame
*dst
, const AVFrame
*src
, int flags
)
311 frame_tmp
= av_frame_alloc();
313 return AVERROR(ENOMEM
);
315 /* if the format is set, use that
316 * otherwise pick the first supported one */
317 if (dst
->format
>= 0) {
318 frame_tmp
->format
= dst
->format
;
320 enum AVPixelFormat
*formats
;
322 ret
= av_hwframe_transfer_get_formats(src
->hw_frames_ctx
,
323 AV_HWFRAME_TRANSFER_DIRECTION_FROM
,
327 frame_tmp
->format
= formats
[0];
330 frame_tmp
->width
= src
->width
;
331 frame_tmp
->height
= src
->height
;
333 ret
= av_frame_get_buffer(frame_tmp
, 32);
337 ret
= av_hwframe_transfer_data(frame_tmp
, src
, flags
);
341 av_frame_move_ref(dst
, frame_tmp
);
344 av_frame_free(&frame_tmp
);
348 int av_hwframe_transfer_data(AVFrame
*dst
, const AVFrame
*src
, int flags
)
350 AVHWFramesContext
*ctx
;
354 return transfer_data_alloc(dst
, src
, flags
);
356 if (src
->hw_frames_ctx
) {
357 ctx
= (AVHWFramesContext
*)src
->hw_frames_ctx
->data
;
359 ret
= ctx
->internal
->hw_type
->transfer_data_from(ctx
, dst
, src
);
362 } else if (dst
->hw_frames_ctx
) {
363 ctx
= (AVHWFramesContext
*)dst
->hw_frames_ctx
->data
;
365 ret
= ctx
->internal
->hw_type
->transfer_data_to(ctx
, dst
, src
);
369 return AVERROR(ENOSYS
);
374 int av_hwframe_get_buffer(AVBufferRef
*hwframe_ref
, AVFrame
*frame
, int flags
)
376 AVHWFramesContext
*ctx
= (AVHWFramesContext
*)hwframe_ref
->data
;
379 if (!ctx
->internal
->hw_type
->frames_get_buffer
)
380 return AVERROR(ENOSYS
);
383 return AVERROR(EINVAL
);
385 frame
->hw_frames_ctx
= av_buffer_ref(hwframe_ref
);
386 if (!frame
->hw_frames_ctx
)
387 return AVERROR(ENOMEM
);
389 ret
= ctx
->internal
->hw_type
->frames_get_buffer(ctx
, frame
);
391 av_buffer_unref(&frame
->hw_frames_ctx
);