vaapi: don't unmap non-existing buffer
[vuplus_xbmc] / lib / 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 "h264.h"
25 #include "vaapi_internal.h"
26
27 /**
28  * @addtogroup VAAPI_Decoding
29  *
30  * @{
31  */
32
33 static void destroy_buffers(VADisplay display, VABufferID *buffers, unsigned int n_buffers)
34 {
35     unsigned int i;
36     for (i = 0; i < n_buffers; i++) {
37         if (buffers[i]) {
38             vaDestroyBuffer(display, buffers[i]);
39             buffers[i] = 0;
40         }
41     }
42 }
43
44 int ff_vaapi_render_picture(struct vaapi_context *vactx, VASurfaceID surface)
45 {
46     VABufferID va_buffers[3];
47     unsigned int n_va_buffers = 0;
48
49     if (vactx->pic_param_buf_id)
50     vaUnmapBuffer(vactx->display, vactx->pic_param_buf_id);
51     va_buffers[n_va_buffers++] = vactx->pic_param_buf_id;
52     }
53
54     if (vactx->iq_matrix_buf_id) {
55         vaUnmapBuffer(vactx->display, vactx->iq_matrix_buf_id);
56         va_buffers[n_va_buffers++] = vactx->iq_matrix_buf_id;
57     }
58
59     if (vactx->bitplane_buf_id) {
60         vaUnmapBuffer(vactx->display, vactx->bitplane_buf_id);
61         va_buffers[n_va_buffers++] = vactx->bitplane_buf_id;
62     }
63
64     if (vaBeginPicture(vactx->display, vactx->context_id,
65                        surface) != VA_STATUS_SUCCESS)
66         return -1;
67
68     if (vaRenderPicture(vactx->display, vactx->context_id,
69                         va_buffers, n_va_buffers) != VA_STATUS_SUCCESS)
70         return -1;
71
72     if (vaRenderPicture(vactx->display, vactx->context_id,
73                         vactx->slice_buf_ids,
74                         vactx->n_slice_buf_ids) != VA_STATUS_SUCCESS)
75         return -1;
76
77     if (vaEndPicture(vactx->display, vactx->context_id) != VA_STATUS_SUCCESS)
78         return -1;
79
80     return 0;
81 }
82
83 int ff_vaapi_commit_slices(struct vaapi_context *vactx)
84 {
85     VABufferID *slice_buf_ids;
86     VABufferID slice_param_buf_id, slice_data_buf_id;
87
88     if (vactx->slice_count == 0)
89         return 0;
90
91     slice_buf_ids =
92         av_fast_realloc(vactx->slice_buf_ids,
93                         &vactx->slice_buf_ids_alloc,
94                         (vactx->n_slice_buf_ids + 2) * sizeof(slice_buf_ids[0]));
95     if (!slice_buf_ids)
96         return -1;
97     vactx->slice_buf_ids = slice_buf_ids;
98
99     slice_param_buf_id = 0;
100     if (vaCreateBuffer(vactx->display, vactx->context_id,
101                        VASliceParameterBufferType,
102                        vactx->slice_param_size,
103                        vactx->slice_count, vactx->slice_params,
104                        &slice_param_buf_id) != VA_STATUS_SUCCESS)
105         return -1;
106     vactx->slice_count = 0;
107
108     slice_data_buf_id = 0;
109     if (vaCreateBuffer(vactx->display, vactx->context_id,
110                        VASliceDataBufferType,
111                        vactx->slice_data_size,
112                        1, (void *)vactx->slice_data,
113                        &slice_data_buf_id) != VA_STATUS_SUCCESS)
114         return -1;
115     vactx->slice_data = NULL;
116     vactx->slice_data_size = 0;
117
118     slice_buf_ids[vactx->n_slice_buf_ids++] = slice_param_buf_id;
119     slice_buf_ids[vactx->n_slice_buf_ids++] = slice_data_buf_id;
120     return 0;
121 }
122
123 static void *alloc_buffer(struct vaapi_context *vactx, int type, unsigned int size, uint32_t *buf_id)
124 {
125     void *data = NULL;
126
127     *buf_id = 0;
128     if (vaCreateBuffer(vactx->display, vactx->context_id,
129                        type, size, 1, NULL, buf_id) == VA_STATUS_SUCCESS)
130         vaMapBuffer(vactx->display, *buf_id, &data);
131
132     return data;
133 }
134
135 void *ff_vaapi_alloc_pic_param(struct vaapi_context *vactx, unsigned int size)
136 {
137     return alloc_buffer(vactx, VAPictureParameterBufferType, size, &vactx->pic_param_buf_id);
138 }
139
140 void *ff_vaapi_alloc_iq_matrix(struct vaapi_context *vactx, unsigned int size)
141 {
142     return alloc_buffer(vactx, VAIQMatrixBufferType, size, &vactx->iq_matrix_buf_id);
143 }
144
145 uint8_t *ff_vaapi_alloc_bitplane(struct vaapi_context *vactx, uint32_t size)
146 {
147     return alloc_buffer(vactx, VABitPlaneBufferType, size, &vactx->bitplane_buf_id);
148 }
149
150 VASliceParameterBufferBase *ff_vaapi_alloc_slice(struct vaapi_context *vactx, const uint8_t *buffer, uint32_t size)
151 {
152     uint8_t *slice_params;
153     VASliceParameterBufferBase *slice_param;
154
155     if (!vactx->slice_data)
156         vactx->slice_data = buffer;
157     if (vactx->slice_data + vactx->slice_data_size != buffer) {
158         if (ff_vaapi_commit_slices(vactx) < 0)
159             return NULL;
160         vactx->slice_data = buffer;
161     }
162
163     slice_params =
164         av_fast_realloc(vactx->slice_params,
165                         &vactx->slice_params_alloc,
166                         (vactx->slice_count + 1) * vactx->slice_param_size);
167     if (!slice_params)
168         return NULL;
169     vactx->slice_params = slice_params;
170
171     slice_param = (VASliceParameterBufferBase *)(slice_params + vactx->slice_count * vactx->slice_param_size);
172     slice_param->slice_data_size   = size;
173     slice_param->slice_data_offset = vactx->slice_data_size;
174     slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
175
176     vactx->slice_count++;
177     vactx->slice_data_size += size;
178     return slice_param;
179 }
180
181 void ff_vaapi_common_end_frame(AVCodecContext *avctx)
182 {
183     struct vaapi_context * const vactx = avctx->hwaccel_context;
184
185     av_dlog(avctx, "ff_vaapi_common_end_frame()\n");
186
187     destroy_buffers(vactx->display, &vactx->pic_param_buf_id, 1);
188     destroy_buffers(vactx->display, &vactx->iq_matrix_buf_id, 1);
189     destroy_buffers(vactx->display, &vactx->bitplane_buf_id, 1);
190     destroy_buffers(vactx->display, vactx->slice_buf_ids, vactx->n_slice_buf_ids);
191     av_freep(&vactx->slice_buf_ids);
192     av_freep(&vactx->slice_params);
193     vactx->n_slice_buf_ids     = 0;
194     vactx->slice_buf_ids_alloc = 0;
195     vactx->slice_count         = 0;
196     vactx->slice_params_alloc  = 0;
197 }
198
199 int ff_vaapi_mpeg_end_frame(AVCodecContext *avctx)
200 {
201     struct vaapi_context * const vactx = avctx->hwaccel_context;
202     MpegEncContext *s = avctx->priv_data;
203     int ret;
204
205     ret = ff_vaapi_commit_slices(vactx);
206     if (ret < 0)
207         goto finish;
208
209     ret = ff_vaapi_render_picture(vactx,
210                                   ff_vaapi_get_surface_id(s->current_picture_ptr));
211     if (ret < 0)
212         goto finish;
213
214     ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
215
216 finish:
217     ff_vaapi_common_end_frame(avctx);
218     return ret;
219 }
220
221 /* @} */