1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg 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.
8 *
9 * FFmpeg 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.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <string.h>
20
24
30
31 #define MAX_REFERENCES 8
32
35
39
40 VAProcFilterCapDeinterlacing
44
49
53
55 {
57 #define D(name) case VAProcDeinterlacing ## name: return #name
62 #undef D
63 default:
64 return "Invalid";
65 }
66 }
67
69 {
72
73 for (
i = 0;
i <
ctx->queue_count;
i++)
76
78 }
79
81 {
84 VAStatus vas;
85 VAProcFilterParameterBufferDeinterlacing params;
87
88 ctx->nb_deint_caps = VAProcDeinterlacingCount;
89 vas = vaQueryVideoProcFilterCaps(vpp_ctx->
hwctx->
display,
91 VAProcFilterDeinterlacing,
94 if (vas != VA_STATUS_SUCCESS) {
96 "caps: %d (%s).\n", vas, vaErrorStr(vas));
98 }
99
100 if (
ctx->mode == VAProcDeinterlacingNone) {
101 for (
i = 0;
i <
ctx->nb_deint_caps;
i++) {
102 if (
ctx->deint_caps[
i].type >
ctx->mode)
103 ctx->mode =
ctx->deint_caps[
i].type;
104 }
106 "deinterlacing mode.\n",
ctx->mode,
108 } else {
109 for (
i = 0;
i <
ctx->nb_deint_caps;
i++) {
110 if (
ctx->deint_caps[
i].type ==
ctx->mode)
111 break;
112 }
113 if (
i >=
ctx->nb_deint_caps) {
115 "not supported.\n",
ctx->mode,
118 }
119 }
120
121 params.type = VAProcFilterDeinterlacing;
122 params.algorithm =
ctx->mode;
124
126 VAProcFilterParameterBufferType,
127 ¶ms,
128 sizeof(params),
129 1);
130 if (vas)
131 return vas;
132
133 vas = vaQueryVideoProcPipelineCaps(vpp_ctx->
hwctx->
display,
136 &
ctx->pipeline_caps);
137 if (vas != VA_STATUS_SUCCESS) {
139 "caps: %d (%s).\n", vas, vaErrorStr(vas));
141 }
142
143 ctx->extra_delay_for_timestamps =
ctx->field_rate == 2 &&
144 ctx->pipeline_caps.num_backward_references == 0;
145
146 ctx->queue_depth =
ctx->pipeline_caps.num_backward_references +
147 ctx->pipeline_caps.num_forward_references +
148 ctx->extra_delay_for_timestamps + 1;
151 "references (%u forward, %u back).\n",
152 ctx->pipeline_caps.num_forward_references,
153 ctx->pipeline_caps.num_backward_references);
155 }
156
157 return 0;
158 }
159
161 {
165 int err;
166
168 if (err < 0)
169 return err;
174
175 return 0;
176 }
177
179 {
185 VASurfaceID input_surface;
188 VAProcPipelineParameterBuffer params;
189 VAProcFilterParameterBufferDeinterlacing *filter_params;
190 VAStatus vas;
191 void *filter_params_addr =
NULL;
192 int err,
i,
field, current_frame_index;
193
194 // NULL frame is used to flush the queue in field mode
195 if (input_frame)
199
200 if (
ctx->queue_count <
ctx->queue_depth) {
201 ctx->frame_queue[
ctx->queue_count++] = input_frame;
202 if (
ctx->queue_count <
ctx->queue_depth) {
203 // Need more reference surfaces before we can continue.
204 return 0;
205 }
206 } else {
208 for (
i = 0;
i + 1 <
ctx->queue_count;
i++)
209 ctx->frame_queue[
i] =
ctx->frame_queue[
i + 1];
210 ctx->frame_queue[
i] = input_frame;
211 }
212
213 current_frame_index =
ctx->pipeline_caps.num_forward_references;
214
215 input_frame =
ctx->frame_queue[current_frame_index];
216 if (!input_frame)
217 return 0;
218
219 input_surface = (VASurfaceID)(uintptr_t)input_frame->
data[3];
220 for (
i = 0;
i <
ctx->pipeline_caps.num_forward_references;
i++)
221 forward_references[
i] = (VASurfaceID)(uintptr_t)
222 ctx->frame_queue[current_frame_index -
i - 1]->data[3];
223 for (
i = 0;
i <
ctx->pipeline_caps.num_backward_references;
i++)
224 backward_references[
i] = (VASurfaceID)(uintptr_t)
225 ctx->frame_queue[current_frame_index +
i + 1]->data[3];
226
228 "deinterlace input.\n", input_surface);
230 for (
i = 0;
i <
ctx->pipeline_caps.num_backward_references;
i++)
234 for (
i = 0;
i <
ctx->pipeline_caps.num_forward_references;
i++)
237
244 }
245
247 if (err < 0)
249
252 if (err < 0)
254
257 &filter_params_addr);
258 if (vas != VA_STATUS_SUCCESS) {
260 "buffer: %d (%s).\n", vas, vaErrorStr(vas));
263 }
264 filter_params = filter_params_addr;
265 filter_params->flags = 0;
267 filter_params->flags |=
field ? VA_DEINTERLACING_BOTTOM_FIELD : 0;
268 } else {
269 filter_params->flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
270 filter_params->flags |=
field ? 0 : VA_DEINTERLACING_BOTTOM_FIELD;
271 }
272 filter_params_addr =
NULL;
274 if (vas != VA_STATUS_SUCCESS)
276 "buffer: %d (%s).\n", vas, vaErrorStr(vas));
277
279 params.num_filters = 1;
280
281 params.forward_references = forward_references;
282 params.num_forward_references =
283 ctx->pipeline_caps.num_forward_references;
284 params.backward_references = backward_references;
285 params.num_backward_references =
286 ctx->pipeline_caps.num_backward_references;
287
288 } else {
289 params.filters =
NULL;
290 params.num_filters = 0;
291 }
292
294 if (err < 0)
296
297 if (
ctx->field_rate == 2) {
302 else
304 ctx->frame_queue[current_frame_index + 1]->pts;
305 }
307
311
313 if (err < 0)
314 break;
315 }
316
317 ctx->prev_pts = input_frame->
pts;
318
319 return err;
320
322 if (filter_params_addr)
325 return err;
326 }
327
329 {
333
336
343
344 return 0;
345 }
346
348 {
350
355
356 return 0;
357 }
358
359 #define OFFSET(x) offsetof(DeintVAAPIContext, x)
360 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
362 { "mode", "Deinterlacing mode",
364 VAProcDeinterlacingNone, VAProcDeinterlacingCount - 1,
FLAGS,
"mode" },
365 { "default", "Use the highest-numbered (and therefore possibly most advanced) deinterlacing algorithm",
367 { "bob", "Use the bob deinterlacing algorithm",
369 { "weave", "Use the weave deinterlacing algorithm",
371 { "motion_adaptive", "Use the motion adaptive deinterlacing algorithm",
373 { "motion_compensated", "Use the motion compensated deinterlacing algorithm",
375
376 { "rate", "Generate output at frame rate or field rate",
378 { "frame", "Output at frame rate (one frame of output for each field-pair)",
380 { "field", "Output at field rate (one frame of output for each field)",
382
383 { "auto", "Only deinterlace fields, passing frames through unchanged",
385
387 };
388
394 };
395
397 {
402 },
403 };
404
406 {
411 },
412 };
413
415 .
name =
"deinterlace_vaapi",
425 };