]> git.sesse.net Git - ffmpeg/blob - libavcodec/vaapi.c
lavf/segment: fix writing separate header with auto BSF
[ffmpeg] / libavcodec / vaapi.c
1 /*
2  * Video Acceleration API (video decoding)
3  * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1
4  *
5  * Copyright (C) 2008-2009 Splitted-Desktop Systems
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 #include "libavutil/log.h"
25 #include "mpegvideo.h"
26 #include "vaapi_internal.h"
27
28 /**
29  * @addtogroup VAAPI_Decoding
30  *
31  * @{
32  */
33
34 static void destroy_buffers(VADisplay display, VABufferID *buffers, unsigned int n_buffers)
35 {
36     unsigned int i;
37     for (i = 0; i < n_buffers; i++) {
38         if (buffers[i] != VA_INVALID_ID) {
39             vaDestroyBuffer(display, buffers[i]);
40             buffers[i] = VA_INVALID_ID;
41         }
42     }
43 }
44
45 int ff_vaapi_context_init(AVCodecContext *avctx)
46 {
47     FFVAContext * const vactx = ff_vaapi_get_context(avctx);
48     const struct vaapi_context * const user_vactx = avctx->hwaccel_context;
49
50     if (!user_vactx) {
51         av_log(avctx, AV_LOG_ERROR, "Hardware acceleration context (hwaccel_context) does not exist.\n");
52         return AVERROR(ENOSYS);
53     }
54
55     vactx->display              = user_vactx->display;
56     vactx->config_id            = user_vactx->config_id;
57     vactx->context_id           = user_vactx->context_id;
58
59     vactx->pic_param_buf_id     = VA_INVALID_ID;
60     vactx->iq_matrix_buf_id     = VA_INVALID_ID;
61     vactx->bitplane_buf_id      = VA_INVALID_ID;
62
63     return 0;
64 }
65
66 int ff_vaapi_context_fini(AVCodecContext *avctx)
67 {
68     return 0;
69 }
70
71 int ff_vaapi_render_picture(FFVAContext *vactx, VASurfaceID surface)
72 {
73     VABufferID va_buffers[3];
74     unsigned int n_va_buffers = 0;
75
76     if (vactx->pic_param_buf_id == VA_INVALID_ID)
77         return 0;
78
79     vaUnmapBuffer(vactx->display, vactx->pic_param_buf_id);
80     va_buffers[n_va_buffers++] = vactx->pic_param_buf_id;
81
82     if (vactx->iq_matrix_buf_id != VA_INVALID_ID) {
83         vaUnmapBuffer(vactx->display, vactx->iq_matrix_buf_id);
84         va_buffers[n_va_buffers++] = vactx->iq_matrix_buf_id;
85     }
86
87     if (vactx->bitplane_buf_id != VA_INVALID_ID) {
88         vaUnmapBuffer(vactx->display, vactx->bitplane_buf_id);
89         va_buffers[n_va_buffers++] = vactx->bitplane_buf_id;
90     }
91
92     if (vaBeginPicture(vactx->display, vactx->context_id,
93                        surface) != VA_STATUS_SUCCESS)
94         return -1;
95
96     if (vaRenderPicture(vactx->display, vactx->context_id,
97                         va_buffers, n_va_buffers) != VA_STATUS_SUCCESS)
98         return -1;
99
100     if (vaRenderPicture(vactx->display, vactx->context_id,
101                         vactx->slice_buf_ids,
102                         vactx->n_slice_buf_ids) != VA_STATUS_SUCCESS)
103         return -1;
104
105     if (vaEndPicture(vactx->display, vactx->context_id) != VA_STATUS_SUCCESS)
106         return -1;
107
108     return 0;
109 }
110
111 int ff_vaapi_commit_slices(FFVAContext *vactx)
112 {
113     VABufferID *slice_buf_ids;
114     VABufferID slice_param_buf_id, slice_data_buf_id;
115
116     if (vactx->slice_count == 0)
117         return 0;
118
119     slice_buf_ids =
120         av_fast_realloc(vactx->slice_buf_ids,
121                         &vactx->slice_buf_ids_alloc,
122                         (vactx->n_slice_buf_ids + 2) * sizeof(slice_buf_ids[0]));
123     if (!slice_buf_ids)
124         return -1;
125     vactx->slice_buf_ids = slice_buf_ids;
126
127     slice_param_buf_id = VA_INVALID_ID;
128     if (vaCreateBuffer(vactx->display, vactx->context_id,
129                        VASliceParameterBufferType,
130                        vactx->slice_param_size,
131                        vactx->slice_count, vactx->slice_params,
132                        &slice_param_buf_id) != VA_STATUS_SUCCESS)
133         return -1;
134     vactx->slice_count = 0;
135
136     slice_data_buf_id = VA_INVALID_ID;
137     if (vaCreateBuffer(vactx->display, vactx->context_id,
138                        VASliceDataBufferType,
139                        vactx->slice_data_size,
140                        1, (void *)vactx->slice_data,
141                        &slice_data_buf_id) != VA_STATUS_SUCCESS)
142         return -1;
143     vactx->slice_data = NULL;
144     vactx->slice_data_size = 0;
145
146     slice_buf_ids[vactx->n_slice_buf_ids++] = slice_param_buf_id;
147     slice_buf_ids[vactx->n_slice_buf_ids++] = slice_data_buf_id;
148     return 0;
149 }
150
151 static void *alloc_buffer(FFVAContext *vactx, int type, unsigned int size, uint32_t *buf_id)
152 {
153     void *data = NULL;
154
155     *buf_id = VA_INVALID_ID;
156     if (vaCreateBuffer(vactx->display, vactx->context_id,
157                        type, size, 1, NULL, buf_id) == VA_STATUS_SUCCESS)
158         vaMapBuffer(vactx->display, *buf_id, &data);
159
160     return data;
161 }
162
163 void *ff_vaapi_alloc_pic_param(FFVAContext *vactx, unsigned int size)
164 {
165     return alloc_buffer(vactx, VAPictureParameterBufferType, size, &vactx->pic_param_buf_id);
166 }
167
168 void *ff_vaapi_alloc_iq_matrix(FFVAContext *vactx, unsigned int size)
169 {
170     return alloc_buffer(vactx, VAIQMatrixBufferType, size, &vactx->iq_matrix_buf_id);
171 }
172
173 uint8_t *ff_vaapi_alloc_bitplane(FFVAContext *vactx, uint32_t size)
174 {
175     return alloc_buffer(vactx, VABitPlaneBufferType, size, &vactx->bitplane_buf_id);
176 }
177
178 VASliceParameterBufferBase *ff_vaapi_alloc_slice(FFVAContext *vactx, const uint8_t *buffer, uint32_t size)
179 {
180     uint8_t *slice_params;
181     VASliceParameterBufferBase *slice_param;
182
183     if (!vactx->slice_data)
184         vactx->slice_data = buffer;
185     if (vactx->slice_data + vactx->slice_data_size != buffer) {
186         if (ff_vaapi_commit_slices(vactx) < 0)
187             return NULL;
188         vactx->slice_data = buffer;
189     }
190
191     slice_params =
192         av_fast_realloc(vactx->slice_params,
193                         &vactx->slice_params_alloc,
194                         (vactx->slice_count + 1) * vactx->slice_param_size);
195     if (!slice_params)
196         return NULL;
197     vactx->slice_params = slice_params;
198
199     slice_param = (VASliceParameterBufferBase *)(slice_params + vactx->slice_count * vactx->slice_param_size);
200     slice_param->slice_data_size   = size;
201     slice_param->slice_data_offset = vactx->slice_data_size;
202     slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
203
204     vactx->slice_count++;
205     vactx->slice_data_size += size;
206     return slice_param;
207 }
208
209 void ff_vaapi_common_end_frame(AVCodecContext *avctx)
210 {
211     FFVAContext * const vactx = ff_vaapi_get_context(avctx);
212
213     destroy_buffers(vactx->display, &vactx->pic_param_buf_id, 1);
214     destroy_buffers(vactx->display, &vactx->iq_matrix_buf_id, 1);
215     destroy_buffers(vactx->display, &vactx->bitplane_buf_id, 1);
216     destroy_buffers(vactx->display, vactx->slice_buf_ids, vactx->n_slice_buf_ids);
217     av_freep(&vactx->slice_buf_ids);
218     av_freep(&vactx->slice_params);
219     vactx->n_slice_buf_ids     = 0;
220     vactx->slice_buf_ids_alloc = 0;
221     vactx->slice_count         = 0;
222     vactx->slice_params_alloc  = 0;
223 }
224
225 #if CONFIG_H263_VAAPI_HWACCEL  || CONFIG_MPEG1_VAAPI_HWACCEL || \
226     CONFIG_MPEG2_VAAPI_HWACCEL || CONFIG_MPEG4_VAAPI_HWACCEL || \
227     CONFIG_VC1_VAAPI_HWACCEL   || CONFIG_WMV3_VAAPI_HWACCEL
228 int ff_vaapi_mpeg_end_frame(AVCodecContext *avctx)
229 {
230     FFVAContext * const vactx = ff_vaapi_get_context(avctx);
231     MpegEncContext *s = avctx->priv_data;
232     int ret;
233
234     ret = ff_vaapi_commit_slices(vactx);
235     if (ret < 0)
236         goto finish;
237
238     ret = ff_vaapi_render_picture(vactx,
239                                   ff_vaapi_get_surface_id(s->current_picture_ptr->f));
240     if (ret < 0)
241         goto finish;
242
243     ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
244
245 finish:
246     ff_vaapi_common_end_frame(avctx);
247     return ret;
248 }
249 #endif
250
251 /* @} */