1 /*****************************************************************************
2 * va_surface.c: libavcodec Generic Video Acceleration helpers
3 *****************************************************************************
4 * Copyright (C) 2009 Geoffroy Couprie
5 * Copyright (C) 2009 Laurent Aimar
6 * Copyright (C) 2015 Steve Lhomme
8 * Authors: Geoffroy Couprie <geal@videolan.org>
9 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
10 * Steve Lhomme <robux4@gmail.com>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_codecs.h>
34 #include <vlc_codec.h>
35 #include <vlc_picture.h>
41 #include "va_surface_internal.h"
45 struct vlc_va_surface_t
{
46 atomic_uintptr_t refcount
;
49 static void DestroyVideoDecoder(vlc_va_t
*va
, va_pool_t
*va_pool
)
51 for (unsigned i
= 0; i
< va_pool
->surface_count
; i
++)
52 va_surface_Release(va_pool
->surface
[i
]->va_surface
);
53 va_pool
->pf_destroy_surfaces(va
);
54 va_pool
->surface_count
= 0;
58 int va_pool_SetupDecoder(vlc_va_t
*va
, va_pool_t
*va_pool
, const AVCodecContext
*avctx
, unsigned count
, int alignment
)
61 unsigned i
= va_pool
->surface_count
;
63 if (avctx
->coded_width
<= 0 || avctx
->coded_height
<= 0)
66 assert((alignment
& (alignment
- 1)) == 0); /* power of 2 */
67 #define ALIGN(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
68 int surface_width
= ALIGN(avctx
->coded_width
, alignment
);
69 int surface_height
= ALIGN(avctx
->coded_height
, alignment
);
71 if (avctx
->coded_width
!= surface_width
|| avctx
->coded_height
!= surface_height
)
72 msg_Warn( va
, "surface dimensions (%dx%d) differ from avcodec dimensions (%dx%d)",
73 surface_width
, surface_height
,
74 avctx
->coded_width
, avctx
->coded_height
);
76 if ( va_pool
->surface_count
>= count
&&
77 va_pool
->surface_width
== surface_width
&&
78 va_pool
->surface_height
== surface_height
)
80 msg_Dbg(va
, "reusing surface pool");
86 DestroyVideoDecoder(va
, va_pool
);
89 msg_Dbg(va
, "va_pool_SetupDecoder id %d %dx%d count: %d", avctx
->codec_id
, avctx
->coded_width
, avctx
->coded_height
, count
);
91 if (count
> MAX_SURFACE_COUNT
)
94 /* FIXME transmit a video_format_t by VaSetup directly */
96 memset(&fmt
, 0, sizeof(fmt
));
97 fmt
.i_width
= surface_width
;
98 fmt
.i_height
= surface_height
;
99 fmt
.i_frame_rate
= avctx
->framerate
.num
;
100 fmt
.i_frame_rate_base
= avctx
->framerate
.den
;
102 err
= va_pool
->pf_create_decoder_surfaces(va
, avctx
->codec_id
, &fmt
, count
);
103 if (err
== VLC_SUCCESS
)
105 va_pool
->surface_width
= surface_width
;
106 va_pool
->surface_height
= surface_height
;
110 va_pool
->surface_count
= i
;
111 if (err
== VLC_SUCCESS
)
112 va_pool
->pf_setup_avcodec_ctx(va
);
117 int va_pool_SetupSurfaces(vlc_va_t
*va
, va_pool_t
*va_pool
, unsigned count
)
119 int err
= VLC_ENOMEM
;
120 unsigned i
= va_pool
->surface_count
;
122 for (i
= 0; i
< count
; i
++) {
123 struct vlc_va_surface_t
*p_surface
= malloc(sizeof(*p_surface
));
124 if (unlikely(p_surface
==NULL
))
126 va_pool
->surface
[i
] = va_pool
->pf_new_surface_context(va
, i
);
127 if (unlikely(va_pool
->surface
[i
]==NULL
))
132 va_pool
->surface
[i
]->va_surface
= p_surface
;
133 atomic_init(&va_pool
->surface
[i
]->va_surface
->refcount
, 1);
138 va_pool
->surface_count
= i
;
139 if (err
== VLC_SUCCESS
)
140 va_pool
->pf_setup_avcodec_ctx(va
);
145 static picture_context_t
*GetSurface(va_pool_t
*va_pool
)
147 for (unsigned i
= 0; i
< va_pool
->surface_count
; i
++) {
148 struct va_pic_context
*surface
= va_pool
->surface
[i
];
149 uintptr_t expected
= 1;
151 if (atomic_compare_exchange_strong(&surface
->va_surface
->refcount
, &expected
, 2))
153 picture_context_t
*field
= surface
->s
.copy(&surface
->s
);
154 /* the copy should have added an extra reference */
155 atomic_fetch_sub(&surface
->va_surface
->refcount
, 1);
162 int va_pool_Get(va_pool_t
*va_pool
, picture_t
*pic
)
164 unsigned tries
= (CLOCK_FREQ
+ VOUT_OUTMEM_SLEEP
) / VOUT_OUTMEM_SLEEP
;
165 picture_context_t
*field
;
167 if (va_pool
->surface_count
== 0)
170 while ((field
= GetSurface(va_pool
)) == NULL
)
174 /* Pool empty. Wait for some time as in src/input/decoder.c.
175 * XXX: Both this and the core should use a semaphore or a CV. */
176 vlc_tick_sleep(VOUT_OUTMEM_SLEEP
);
178 pic
->context
= field
;
182 void va_surface_AddRef(vlc_va_surface_t
*surface
)
184 atomic_fetch_add(&surface
->refcount
, 1);
187 void va_surface_Release(vlc_va_surface_t
*surface
)
189 if (atomic_fetch_sub(&surface
->refcount
, 1) != 1)
194 void va_pool_Close(vlc_va_t
*va
, va_pool_t
*va_pool
)
196 DestroyVideoDecoder(va
, va_pool
);
197 va_pool
->pf_destroy_video_service(va
);
198 if (va_pool
->pf_destroy_device_manager
)
199 va_pool
->pf_destroy_device_manager(va
);
200 va_pool
->pf_destroy_device(va
);
203 int va_pool_Open(vlc_va_t
*va
, va_pool_t
*va_pool
)
206 if (va_pool
->pf_create_device(va
)) {
207 msg_Err(va
, "Failed to create device");
210 msg_Dbg(va
, "CreateDevice succeed");
212 if (va_pool
->pf_create_device_manager
&&
213 va_pool
->pf_create_device_manager(va
) != VLC_SUCCESS
) {
214 msg_Err(va
, "CreateDeviceManager failed");
218 if (va_pool
->pf_create_video_service(va
)) {
219 msg_Err(va
, "CreateVideoService failed");