1 /*****************************************************************************
2 * video_output.c
3 *****************************************************************************
4 * Copyright (C) 2013-2015 L-SMASH Works project
5 *
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
20
21 /* This file is available under an ISC license. */
22
23 #include <string.h>
24
25 /* Libav */
26 #include <libavcodec/avcodec.h> /* Decoder */
27 #include <libswscale/swscale.h> /* Colorspace converter */
28 #include <libavutil/imgutils.h>
29 #include <libavutil/mem.h>
30
31 #include "lsmashsource.h"
32 #include "video_output.h"
33
34 typedef struct
35 {
36 uint8_t *data [4];
37 int linesize[4];
38 } vs_picture_t;
39
make_black_background_planar_yuv8(VSFrameRef * vs_frame,const VSAPI * vsapi)40 static void make_black_background_planar_yuv8
41 (
42 VSFrameRef *vs_frame,
43 const VSAPI *vsapi
44 )
45 {
46 for( int i = 0; i < 3; i++ )
47 memset( vsapi->getWritePtr( vs_frame, i ), i ? 0x80 : 0x00, vsapi->getStride( vs_frame, i ) * vsapi->getFrameHeight( vs_frame, i ) );
48 }
49
make_black_background_planar_yuv16(VSFrameRef * vs_frame,const VSAPI * vsapi)50 static void make_black_background_planar_yuv16
51 (
52 VSFrameRef *vs_frame,
53 const VSAPI *vsapi
54 )
55 {
56 int shift = vsapi->getFrameFormat( vs_frame )->bitsPerSample - 8;
57 for( int i = 0; i < 3; i++ )
58 {
59 int v = i ? 0x00000080 << shift : 0x00000000;
60 uint8_t *data = vsapi->getWritePtr( vs_frame, i );
61 uint8_t *end = data + vsapi->getStride( vs_frame, i ) * vsapi->getFrameHeight( vs_frame, i );
62 while( data < end )
63 {
64 /* Assume little endianess. */
65 data[0] = v;
66 data[1] = v >> 8;
67 data += 2;
68 }
69 }
70 }
71
make_black_background_planar_rgb(VSFrameRef * vs_frame,const VSAPI * vsapi)72 static void make_black_background_planar_rgb
73 (
74 VSFrameRef *vs_frame,
75 const VSAPI *vsapi
76 )
77 {
78 for( int i = 0; i < 3; i++ )
79 memset( vsapi->getWritePtr( vs_frame, i ), 0x00, vsapi->getStride( vs_frame, i ) * vsapi->getFrameHeight( vs_frame, i ) );
80 }
81
make_frame_planar_yuv(lw_video_scaler_handler_t * vshp,AVFrame * av_picture,const component_reorder_t * component_reorder,VSFrameRef * vs_frame,VSFrameContext * frame_ctx,const VSAPI * vsapi)82 static void make_frame_planar_yuv
83 (
84 lw_video_scaler_handler_t *vshp,
85 AVFrame *av_picture,
86 const component_reorder_t *component_reorder,
87 VSFrameRef *vs_frame,
88 VSFrameContext *frame_ctx,
89 const VSAPI *vsapi
90 )
91 {
92 vs_picture_t vs_picture =
93 {
94 /* data */
95 {
96 vsapi->getWritePtr( vs_frame, 0 ),
97 vsapi->getWritePtr( vs_frame, 1 ),
98 vsapi->getWritePtr( vs_frame, 2 ),
99 NULL
100 },
101 /* linesize */
102 {
103 vsapi->getStride( vs_frame, 0 ),
104 vsapi->getStride( vs_frame, 1 ),
105 vsapi->getStride( vs_frame, 2 ),
106 0
107 }
108 };
109 sws_scale( vshp->sws_ctx, (const uint8_t* const*)av_picture->data, av_picture->linesize, 0, av_picture->height, vs_picture.data, vs_picture.linesize );
110 }
111
make_frame_planar_rgb(lw_video_scaler_handler_t * vshp,AVFrame * av_picture,const component_reorder_t * component_reorder,VSFrameRef * vs_frame,VSFrameContext * frame_ctx,const VSAPI * vsapi)112 static void make_frame_planar_rgb
113 (
114 lw_video_scaler_handler_t *vshp,
115 AVFrame *av_picture,
116 const component_reorder_t *component_reorder,
117 VSFrameRef *vs_frame,
118 VSFrameContext *frame_ctx,
119 const VSAPI *vsapi
120 )
121 {
122 vs_picture_t vs_picture =
123 {
124 /* data */
125 {
126 vsapi->getWritePtr( vs_frame, component_reorder[0] ),
127 vsapi->getWritePtr( vs_frame, component_reorder[1] ),
128 vsapi->getWritePtr( vs_frame, component_reorder[2] ),
129 NULL
130 },
131 /* linesize */
132 {
133 vsapi->getStride( vs_frame, component_reorder[0] ),
134 vsapi->getStride( vs_frame, component_reorder[1] ),
135 vsapi->getStride( vs_frame, component_reorder[2] ),
136 0
137 }
138
139 };
140 sws_scale( vshp->sws_ctx, (const uint8_t* const*)av_picture->data, av_picture->linesize, 0, av_picture->height, vs_picture.data, vs_picture.linesize );
141 }
142
make_frame_planar_rgb8(lw_video_scaler_handler_t * vshp,AVFrame * av_picture,const component_reorder_t * component_reorder,VSFrameRef * vs_frame,VSFrameContext * frame_ctx,const VSAPI * vsapi)143 static void make_frame_planar_rgb8
144 (
145 lw_video_scaler_handler_t *vshp,
146 AVFrame *av_picture,
147 const component_reorder_t *component_reorder,
148 VSFrameRef *vs_frame,
149 VSFrameContext *frame_ctx,
150 const VSAPI *vsapi
151 )
152 {
153 uint8_t *vs_frame_data[3] =
154 {
155 vsapi->getWritePtr( vs_frame, 0 ),
156 vsapi->getWritePtr( vs_frame, 1 ),
157 vsapi->getWritePtr( vs_frame, 2 )
158 };
159 const VSFormat *vs_format = vsapi->getFrameFormat( vs_frame );
160 int av_num_components = vs_format->numPlanes + (component_reorder[3] == -1 ? 0 : 1);
161 int vs_frame_linesize = vsapi->getStride( vs_frame, 0 );
162 int vs_pixel_offset = 0;
163 int av_pixel_offset = 0;
164 for( int i = 0; i < av_picture->height; i++ )
165 {
166 uint8_t *av_pixel = av_picture->data[0] + av_pixel_offset;
167 uint8_t *av_pixel_r = av_pixel + component_reorder[0];
168 uint8_t *av_pixel_g = av_pixel + component_reorder[1];
169 uint8_t *av_pixel_b = av_pixel + component_reorder[2];
170 uint8_t *vs_pixel_r = vs_frame_data[0] + vs_pixel_offset;
171 uint8_t *vs_pixel_g = vs_frame_data[1] + vs_pixel_offset;
172 uint8_t *vs_pixel_b = vs_frame_data[2] + vs_pixel_offset;
173 for( int j = 0; j < av_picture->width; j++ )
174 {
175 *(vs_pixel_r++) = *av_pixel_r;
176 *(vs_pixel_g++) = *av_pixel_g;
177 *(vs_pixel_b++) = *av_pixel_b;
178 av_pixel_r += av_num_components;
179 av_pixel_g += av_num_components;
180 av_pixel_b += av_num_components;
181 }
182 av_pixel_offset += av_picture->linesize[0];
183 vs_pixel_offset += vs_frame_linesize;
184 }
185 }
186
make_frame_planar_rgb16(lw_video_scaler_handler_t * vshp,AVFrame * av_picture,const component_reorder_t * component_reorder,VSFrameRef * vs_frame,VSFrameContext * frame_ctx,const VSAPI * vsapi)187 static void make_frame_planar_rgb16
188 (
189 lw_video_scaler_handler_t *vshp,
190 AVFrame *av_picture,
191 const component_reorder_t *component_reorder,
192 VSFrameRef *vs_frame,
193 VSFrameContext *frame_ctx,
194 const VSAPI *vsapi
195 )
196 {
197 uint8_t *vs_frame_data[3] =
198 {
199 vsapi->getWritePtr( vs_frame, 0 ),
200 vsapi->getWritePtr( vs_frame, 1 ),
201 vsapi->getWritePtr( vs_frame, 2 )
202 };
203 const VSFormat *vs_format = vsapi->getFrameFormat( vs_frame );
204 int av_num_components = vs_format->numPlanes + (component_reorder[3] == -1 ? 0 : 1);
205 int vs_frame_linesize = vsapi->getStride( vs_frame, 0 );
206 int vs_pixel_offset = 0;
207 int av_pixel_offset = 0;
208 for( int i = 0; i < av_picture->height; i++ )
209 {
210 uint16_t *av_pixel = (uint16_t *)(av_picture->data[0] + av_pixel_offset);
211 uint16_t *av_pixel_r = av_pixel + component_reorder[0];
212 uint16_t *av_pixel_g = av_pixel + component_reorder[1];
213 uint16_t *av_pixel_b = av_pixel + component_reorder[2];
214 uint16_t *vs_pixel_r = (uint16_t *)(vs_frame_data[0] + vs_pixel_offset);
215 uint16_t *vs_pixel_g = (uint16_t *)(vs_frame_data[1] + vs_pixel_offset);
216 uint16_t *vs_pixel_b = (uint16_t *)(vs_frame_data[2] + vs_pixel_offset);
217 for( int j = 0; j < av_picture->width; j++ )
218 {
219 *(vs_pixel_r++) = *av_pixel_r;
220 *(vs_pixel_g++) = *av_pixel_g;
221 *(vs_pixel_b++) = *av_pixel_b;
222 av_pixel_r += av_num_components;
223 av_pixel_g += av_num_components;
224 av_pixel_b += av_num_components;
225 }
226 av_pixel_offset += av_picture->linesize[0];
227 vs_pixel_offset += vs_frame_linesize;
228 }
229 }
230
get_vs_output_pixel_format(const char * format_name)231 VSPresetFormat get_vs_output_pixel_format( const char *format_name )
232 {
233 if( !format_name )
234 return pfNone;
235 static const struct
236 {
237 const char *format_name;
238 VSPresetFormat vs_output_pixel_format;
239 } format_table[] =
240 {
241 { "YUV420P8", pfYUV420P8 },
242 { "YUV422P8", pfYUV422P8 },
243 { "YUV444P8", pfYUV444P8 },
244 { "YUV410P8", pfYUV410P8 },
245 { "YUV411P8", pfYUV411P8 },
246 { "YUV440P8", pfYUV440P8 },
247 { "YUV420P9", pfYUV420P9 },
248 { "YUV422P9", pfYUV422P9 },
249 { "YUV444P9", pfYUV444P9 },
250 { "YUV420P10", pfYUV420P10 },
251 { "YUV422P10", pfYUV422P10 },
252 { "YUV444P10", pfYUV444P10 },
253 { "YUV420P16", pfYUV420P16 },
254 { "YUV422P16", pfYUV422P16 },
255 { "YUV444P16", pfYUV444P16 },
256 { "RGB24", pfRGB24 },
257 { "RGB27", pfRGB27 },
258 { "RGB30", pfRGB30 },
259 { "RGB48", pfRGB48 },
260 { NULL, pfNone }
261 };
262 for( int i = 0; format_table[i].format_name; i++ )
263 if( strcasecmp( format_name, format_table[i].format_name ) == 0 )
264 return format_table[i].vs_output_pixel_format;
265 return pfNone;
266 }
267
vs_to_av_output_pixel_format(VSPresetFormat vs_output_pixel_format)268 static enum AVPixelFormat vs_to_av_output_pixel_format( VSPresetFormat vs_output_pixel_format )
269 {
270 static const struct
271 {
272 VSPresetFormat vs_output_pixel_format;
273 enum AVPixelFormat av_output_pixel_format;
274 } format_table[] =
275 {
276 { pfYUV420P8, AV_PIX_FMT_YUV420P },
277 { pfYUV422P8, AV_PIX_FMT_YUV422P },
278 { pfYUV444P8, AV_PIX_FMT_YUV444P },
279 { pfYUV410P8, AV_PIX_FMT_YUV410P },
280 { pfYUV411P8, AV_PIX_FMT_YUV411P },
281 { pfYUV440P8, AV_PIX_FMT_YUV440P },
282 { pfYUV420P9, AV_PIX_FMT_YUV420P9LE },
283 { pfYUV422P9, AV_PIX_FMT_YUV422P9LE },
284 { pfYUV444P9, AV_PIX_FMT_YUV444P9LE },
285 { pfYUV420P10, AV_PIX_FMT_YUV420P10LE },
286 { pfYUV422P10, AV_PIX_FMT_YUV422P10LE },
287 { pfYUV444P10, AV_PIX_FMT_YUV444P10LE },
288 { pfYUV420P16, AV_PIX_FMT_YUV420P16LE },
289 { pfYUV422P16, AV_PIX_FMT_YUV422P16LE },
290 { pfYUV444P16, AV_PIX_FMT_YUV444P16LE },
291 { pfRGB24, AV_PIX_FMT_GBRP },
292 { pfRGB27, AV_PIX_FMT_GBRP9LE },
293 { pfRGB30, AV_PIX_FMT_GBRP10LE },
294 { pfRGB48, AV_PIX_FMT_GBRP16LE },
295 { pfNone, AV_PIX_FMT_NONE }
296 };
297 for( int i = 0; format_table[i].vs_output_pixel_format != pfNone; i++ )
298 if( vs_output_pixel_format == format_table[i].vs_output_pixel_format )
299 return format_table[i].av_output_pixel_format;
300 return AV_PIX_FMT_NONE;
301 }
302
get_component_reorder(enum AVPixelFormat av_output_pixel_format)303 static const component_reorder_t *get_component_reorder( enum AVPixelFormat av_output_pixel_format )
304 {
305 static const struct
306 {
307 enum AVPixelFormat av_output_pixel_format;
308 component_reorder_t component_reorder[4];
309 } reorder_table[] =
310 {
311 /* YUV */
312 { AV_PIX_FMT_YUV420P, { 0, 1, 2, -1 } },
313 { AV_PIX_FMT_YUV422P, { 0, 1, 2, -1 } },
314 { AV_PIX_FMT_YUV444P, { 0, 1, 2, -1 } },
315 { AV_PIX_FMT_YUV410P, { 0, 1, 2, -1 } },
316 { AV_PIX_FMT_YUV411P, { 0, 1, 2, -1 } },
317 { AV_PIX_FMT_YUV440P, { 0, 1, 2, -1 } },
318 { AV_PIX_FMT_YUV420P9LE, { 0, 1, 2, -1 } },
319 { AV_PIX_FMT_YUV422P9LE, { 0, 1, 2, -1 } },
320 { AV_PIX_FMT_YUV444P9LE, { 0, 1, 2, -1 } },
321 { AV_PIX_FMT_YUV420P10LE, { 0, 1, 2, -1 } },
322 { AV_PIX_FMT_YUV422P10LE, { 0, 1, 2, -1 } },
323 { AV_PIX_FMT_YUV444P10LE, { 0, 1, 2, -1 } },
324 { AV_PIX_FMT_YUV420P16LE, { 0, 1, 2, -1 } },
325 { AV_PIX_FMT_YUV422P16LE, { 0, 1, 2, -1 } },
326 { AV_PIX_FMT_YUV444P16LE, { 0, 1, 2, -1 } },
327 /* RGB */
328 { AV_PIX_FMT_GBRP, { 1, 2, 0, -1 } },
329 { AV_PIX_FMT_GBRP9LE, { 1, 2, 0, -1 } },
330 { AV_PIX_FMT_GBRP10LE, { 1, 2, 0, -1 } },
331 { AV_PIX_FMT_GBRP16LE, { 1, 2, 0, -1 } },
332 { AV_PIX_FMT_RGB24, { 0, 1, 2, -1 } },
333 { AV_PIX_FMT_ARGB, { 1, 2, 3, 0 } },
334 { AV_PIX_FMT_RGBA, { 0, 1, 2, 3 } },
335 { AV_PIX_FMT_ABGR, { 3, 2, 1, 0 } },
336 { AV_PIX_FMT_BGRA, { 2, 1, 0, 3 } },
337 { AV_PIX_FMT_BGR48LE, { 2, 1, 0, -1 } },
338 { AV_PIX_FMT_NONE, { 0, 1, 2, 3 } }
339 };
340 int i = 0;
341 while( reorder_table[i].av_output_pixel_format != AV_PIX_FMT_NONE )
342 {
343 if( av_output_pixel_format == reorder_table[i].av_output_pixel_format )
344 break;
345 ++i;
346 }
347 return reorder_table[i].component_reorder;
348 }
349
set_frame_maker(vs_video_output_handler_t * vs_vohp,int av_output_is_planar_rgb)350 static inline int set_frame_maker
351 (
352 vs_video_output_handler_t *vs_vohp,
353 int av_output_is_planar_rgb
354 )
355 {
356 static const struct
357 {
358 VSPresetFormat vs_output_pixel_format;
359 int av_output_is_planar_rgb;
360 func_make_black_background *func_make_black_background;
361 func_make_frame *func_make_frame;
362 } frame_maker_table[] =
363 {
364 { pfYUV420P8, 0, make_black_background_planar_yuv8, make_frame_planar_yuv },
365 { pfYUV422P8, 0, make_black_background_planar_yuv8, make_frame_planar_yuv },
366 { pfYUV444P8, 0, make_black_background_planar_yuv8, make_frame_planar_yuv },
367 { pfYUV410P8, 0, make_black_background_planar_yuv8, make_frame_planar_yuv },
368 { pfYUV411P8, 0, make_black_background_planar_yuv8, make_frame_planar_yuv },
369 { pfYUV440P8, 0, make_black_background_planar_yuv8, make_frame_planar_yuv },
370 { pfYUV420P9, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
371 { pfYUV422P9, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
372 { pfYUV444P9, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
373 { pfYUV420P10, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
374 { pfYUV422P10, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
375 { pfYUV444P10, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
376 { pfYUV420P16, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
377 { pfYUV422P16, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
378 { pfYUV444P16, 0, make_black_background_planar_yuv16, make_frame_planar_yuv },
379 { pfRGB24, 1, make_black_background_planar_rgb, make_frame_planar_rgb },
380 { pfRGB27, 1, make_black_background_planar_rgb, make_frame_planar_rgb },
381 { pfRGB30, 1, make_black_background_planar_rgb, make_frame_planar_rgb },
382 { pfRGB48, 1, make_black_background_planar_rgb, make_frame_planar_rgb },
383 { pfRGB24, 0, make_black_background_planar_rgb, make_frame_planar_rgb8 },
384 { pfRGB48, 0, make_black_background_planar_rgb, make_frame_planar_rgb16 },
385 { pfNone, 0, NULL, NULL }
386 };
387 for( int i = 0; frame_maker_table[i].vs_output_pixel_format != pfNone; i++ )
388 if( vs_vohp->vs_output_pixel_format == frame_maker_table[i].vs_output_pixel_format
389 && av_output_is_planar_rgb == frame_maker_table[i].av_output_is_planar_rgb )
390 {
391 vs_vohp->make_black_background = frame_maker_table[i].func_make_black_background;
392 vs_vohp->make_frame = frame_maker_table[i].func_make_frame;
393 return 0;
394 }
395 vs_vohp->make_black_background = NULL;
396 vs_vohp->make_frame = NULL;
397 return -1;
398 }
399
determine_colorspace_conversion(vs_video_output_handler_t * vs_vohp,enum AVPixelFormat input_pixel_format,enum AVPixelFormat * output_pixel_format)400 static int determine_colorspace_conversion
401 (
402 vs_video_output_handler_t *vs_vohp,
403 enum AVPixelFormat input_pixel_format,
404 enum AVPixelFormat *output_pixel_format
405 )
406 {
407 int fmt_conv_required = 1;
408 avoid_yuv_scale_conversion( &input_pixel_format );
409 static const struct
410 {
411 enum AVPixelFormat av_input_pixel_format;
412 VSPresetFormat vs_output_pixel_format;
413 int fmt_conv_required;
414 } conversion_table[] =
415 {
416 { AV_PIX_FMT_YUV420P, pfYUV420P8, 0 },
417 { AV_PIX_FMT_NV12, pfYUV420P8, 1 },
418 { AV_PIX_FMT_NV21, pfYUV420P8, 1 },
419 { AV_PIX_FMT_YUV422P, pfYUV422P8, 0 },
420 { AV_PIX_FMT_UYVY422, pfYUV422P8, 1 },
421 { AV_PIX_FMT_YUYV422, pfYUV422P8, 1 },
422 { AV_PIX_FMT_YUV444P, pfYUV444P8, 0 },
423 { AV_PIX_FMT_YUV410P, pfYUV410P8, 0 },
424 { AV_PIX_FMT_YUV411P, pfYUV411P8, 0 },
425 { AV_PIX_FMT_UYYVYY411, pfYUV411P8, 1 },
426 { AV_PIX_FMT_YUV440P, pfYUV440P8, 0 },
427 { AV_PIX_FMT_YUV420P9LE, pfYUV420P9, 0 },
428 { AV_PIX_FMT_YUV420P9BE, pfYUV420P9, 1 },
429 { AV_PIX_FMT_YUV422P9LE, pfYUV422P9, 0 },
430 { AV_PIX_FMT_YUV422P9BE, pfYUV422P9, 1 },
431 { AV_PIX_FMT_YUV444P9LE, pfYUV444P9, 0 },
432 { AV_PIX_FMT_YUV444P9BE, pfYUV444P9, 1 },
433 { AV_PIX_FMT_YUV420P10LE, pfYUV420P10, 0 },
434 { AV_PIX_FMT_YUV420P10BE, pfYUV420P10, 1 },
435 { AV_PIX_FMT_YUV422P10LE, pfYUV422P10, 0 },
436 { AV_PIX_FMT_YUV422P10BE, pfYUV422P10, 1 },
437 { AV_PIX_FMT_YUV444P10LE, pfYUV444P10, 0 },
438 { AV_PIX_FMT_YUV444P10BE, pfYUV444P10, 1 },
439 { AV_PIX_FMT_YUV420P16LE, pfYUV420P16, 0 },
440 { AV_PIX_FMT_YUV420P16BE, pfYUV420P16, 1 },
441 { AV_PIX_FMT_YUV422P16LE, pfYUV422P16, 0 },
442 { AV_PIX_FMT_YUV422P16BE, pfYUV422P16, 1 },
443 { AV_PIX_FMT_YUV444P16LE, pfYUV444P16, 0 },
444 { AV_PIX_FMT_YUV444P16BE, pfYUV444P16, 1 },
445 { AV_PIX_FMT_GBRP, pfRGB24, 0 },
446 { AV_PIX_FMT_GBRP9LE, pfRGB48, 0 },
447 { AV_PIX_FMT_GBRP9BE, pfRGB48, 1 },
448 { AV_PIX_FMT_GBRP10LE, pfRGB48, 0 },
449 { AV_PIX_FMT_GBRP10BE, pfRGB48, 1 },
450 { AV_PIX_FMT_GBRP16LE, pfRGB48, 0 },
451 { AV_PIX_FMT_GBRP16BE, pfRGB48, 1 },
452 { AV_PIX_FMT_BGR24, pfRGB24, 0 },
453 { AV_PIX_FMT_RGB24, pfRGB24, 0 },
454 { AV_PIX_FMT_ARGB, pfRGB24, 0 },
455 { AV_PIX_FMT_RGBA, pfRGB24, 0 },
456 { AV_PIX_FMT_ABGR, pfRGB24, 0 },
457 { AV_PIX_FMT_BGRA, pfRGB24, 0 },
458 { AV_PIX_FMT_BGR48LE, pfRGB48, 0 },
459 { AV_PIX_FMT_BGR48BE, pfRGB48, 1 },
460 { AV_PIX_FMT_NONE, pfNone, 1 }
461 };
462 if( vs_vohp->variable_info || vs_vohp->vs_output_pixel_format == pfNone )
463 {
464 /* Determine by input pixel format. */
465 for( int i = 0; conversion_table[i].vs_output_pixel_format != pfNone; i++ )
466 if( input_pixel_format == conversion_table[i].av_input_pixel_format )
467 {
468 vs_vohp->vs_output_pixel_format = conversion_table[i].vs_output_pixel_format;
469 fmt_conv_required = conversion_table[i].fmt_conv_required;
470 break;
471 }
472 }
473 else
474 {
475 /* Determine by both input pixel format and output pixel format. */
476 for( int i = 0; conversion_table[i].vs_output_pixel_format != pfNone; i++ )
477 {
478 if( input_pixel_format == conversion_table[i].av_input_pixel_format
479 && vs_vohp->vs_output_pixel_format == conversion_table[i].vs_output_pixel_format )
480 {
481 fmt_conv_required = conversion_table[i].fmt_conv_required;
482 break;
483 }
484 }
485 }
486 *output_pixel_format = fmt_conv_required
487 ? vs_to_av_output_pixel_format( vs_vohp->vs_output_pixel_format )
488 : input_pixel_format;
489 vs_vohp->component_reorder = get_component_reorder( *output_pixel_format );
490 int av_output_flags = av_pix_fmt_desc_get( *output_pixel_format )->flags;
491 return set_frame_maker( vs_vohp, (av_output_flags & AV_PIX_FMT_FLAG_PLANAR) && (av_output_flags & AV_PIX_FMT_FLAG_RGB) );
492 }
493
494 typedef struct
495 {
496 VSFrameRef *vs_frame_buffer;
497 const VSAPI *vsapi;
498 } vs_video_buffer_handler_t;
499
new_output_video_frame(vs_video_output_handler_t * vs_vohp,const AVFrame * av_frame,enum AVPixelFormat * output_pixel_format,int input_pix_fmt_change,VSFrameContext * frame_ctx,VSCore * core,const VSAPI * vsapi)500 static VSFrameRef *new_output_video_frame
501 (
502 vs_video_output_handler_t *vs_vohp,
503 const AVFrame *av_frame,
504 enum AVPixelFormat *output_pixel_format,
505 int input_pix_fmt_change,
506 VSFrameContext *frame_ctx,
507 VSCore *core,
508 const VSAPI *vsapi
509 )
510 {
511 if( vs_vohp->variable_info )
512 {
513 if( !av_frame->opaque
514 && determine_colorspace_conversion( vs_vohp, av_frame->format, output_pixel_format ) < 0 )
515 goto fail;
516 const VSFormat *vs_format = vsapi->getFormatPreset( vs_vohp->vs_output_pixel_format, core );
517 return vsapi->newVideoFrame( vs_format, av_frame->width, av_frame->height, NULL, core );
518 }
519 else
520 {
521 if( !av_frame->opaque
522 && input_pix_fmt_change
523 && determine_colorspace_conversion( vs_vohp, av_frame->format, output_pixel_format ) < 0 )
524 goto fail;
525 return vsapi->copyFrame( vs_vohp->background_frame, core );
526 }
527 fail:
528 if( frame_ctx )
529 vsapi->setFilterError( "lsmas: failed to determine colorspace conversion.", frame_ctx );
530 return NULL;
531 }
532
make_frame(lw_video_output_handler_t * vohp,AVFrame * av_frame)533 VSFrameRef *make_frame
534 (
535 lw_video_output_handler_t *vohp,
536 AVFrame *av_frame
537 )
538 {
539 vs_video_output_handler_t *vs_vohp = (vs_video_output_handler_t *)vohp->private_handler;
540 lw_video_scaler_handler_t *vshp = &vohp->scaler;
541 VSFrameContext *frame_ctx = vs_vohp->frame_ctx;
542 VSCore *core = vs_vohp->core;
543 const VSAPI *vsapi = vs_vohp->vsapi;
544 if( av_frame->opaque )
545 {
546 /* Render from the decoder directly. */
547 vs_video_buffer_handler_t *vs_vbhp = (vs_video_buffer_handler_t *)av_frame->opaque;
548 return vs_vbhp ? (VSFrameRef *)vs_vbhp->vsapi->cloneFrameRef( vs_vbhp->vs_frame_buffer ) : NULL;
549 }
550 if( !vs_vohp->make_frame )
551 return NULL;
552 /* Make video frame.
553 * Convert pixel format if needed. We don't change the presentation resolution. */
554 VSFrameRef *vs_frame = new_output_video_frame( vs_vohp, av_frame,
555 &vshp->output_pixel_format,
556 !!(vshp->frame_prop_change_flags & LW_FRAME_PROP_CHANGE_FLAG_PIXEL_FORMAT),
557 frame_ctx, core, vsapi );
558 if( vs_frame )
559 vs_vohp->make_frame( vshp, av_frame, vs_vohp->component_reorder, vs_frame, frame_ctx, vsapi );
560 else if( frame_ctx )
561 vsapi->setFilterError( "lsmas: failed to allocate a output video frame.", frame_ctx );
562 return vs_frame;
563 }
564
vs_check_dr_available(AVCodecContext * ctx,enum AVPixelFormat pixel_format)565 static int vs_check_dr_available
566 (
567 AVCodecContext *ctx,
568 enum AVPixelFormat pixel_format
569 )
570 {
571 if( !(ctx->codec->capabilities & AV_CODEC_CAP_DR1) )
572 return 0;
573 static enum AVPixelFormat dr_support_pix_fmt[] =
574 {
575 AV_PIX_FMT_YUV420P,
576 AV_PIX_FMT_YUV422P,
577 AV_PIX_FMT_YUV444P,
578 AV_PIX_FMT_YUV410P,
579 AV_PIX_FMT_YUV411P,
580 AV_PIX_FMT_YUV440P,
581 AV_PIX_FMT_YUV420P9LE,
582 AV_PIX_FMT_YUV422P9LE,
583 AV_PIX_FMT_YUV444P9LE,
584 AV_PIX_FMT_YUV420P10LE,
585 AV_PIX_FMT_YUV422P10LE,
586 AV_PIX_FMT_YUV444P10LE,
587 AV_PIX_FMT_YUV420P16LE,
588 AV_PIX_FMT_YUV422P16LE,
589 AV_PIX_FMT_YUV444P16LE,
590 AV_PIX_FMT_GBRP,
591 AV_PIX_FMT_GBRP9LE,
592 AV_PIX_FMT_GBRP10LE,
593 AV_PIX_FMT_GBRP16LE,
594 AV_PIX_FMT_NONE
595 };
596 for( int i = 0; dr_support_pix_fmt[i] != AV_PIX_FMT_NONE; i++ )
597 if( dr_support_pix_fmt[i] == pixel_format )
598 return 1;
599 return 0;
600 }
601
vs_video_release_buffer_handler(void * opaque,uint8_t * data)602 static void vs_video_release_buffer_handler
603 (
604 void *opaque,
605 uint8_t *data
606 )
607 {
608 vs_video_buffer_handler_t *vs_vbhp = (vs_video_buffer_handler_t *)opaque;
609 if( !vs_vbhp )
610 return;
611 if( vs_vbhp->vsapi && vs_vbhp->vsapi->freeFrame )
612 vs_vbhp->vsapi->freeFrame( vs_vbhp->vs_frame_buffer );
613 free( vs_vbhp );
614 }
615
vs_video_unref_buffer_handler(void * opaque,uint8_t * data)616 static void vs_video_unref_buffer_handler
617 (
618 void *opaque,
619 uint8_t *data
620 )
621 {
622 /* Decrement the reference-counter to the video buffer handler by 1.
623 * Delete it by vs_video_release_buffer_handler() if there are no reference to it i.e. the reference-counter equals zero. */
624 AVBufferRef *vs_buffer_ref = (AVBufferRef *)opaque;
625 av_buffer_unref( &vs_buffer_ref );
626 }
627
vs_create_plane_buffer(vs_video_buffer_handler_t * vs_vbhp,AVBufferRef * vs_buffer_handler,AVFrame * av_frame,int av_plane,int vs_plane)628 static inline int vs_create_plane_buffer
629 (
630 vs_video_buffer_handler_t *vs_vbhp,
631 AVBufferRef *vs_buffer_handler,
632 AVFrame *av_frame,
633 int av_plane,
634 int vs_plane
635 )
636 {
637 AVBufferRef *vs_buffer_ref = av_buffer_ref( vs_buffer_handler );
638 if( !vs_buffer_ref )
639 {
640 av_buffer_unref( &vs_buffer_handler );
641 return -1;
642 }
643 av_frame->linesize[av_plane] = vs_vbhp->vsapi->getStride( vs_vbhp->vs_frame_buffer, vs_plane );
644 int vs_plane_size = vs_vbhp->vsapi->getFrameHeight( vs_vbhp->vs_frame_buffer, vs_plane )
645 * av_frame->linesize[av_plane];
646 av_frame->buf[av_plane] = av_buffer_create( vs_vbhp->vsapi->getWritePtr( vs_vbhp->vs_frame_buffer, vs_plane ),
647 vs_plane_size,
648 vs_video_unref_buffer_handler,
649 vs_buffer_ref,
650 0 );
651 if( !av_frame->buf[av_plane] )
652 return -1;
653 av_frame->data[av_plane] = av_frame->buf[av_plane]->data;
654 return 0;
655 }
656
vs_video_get_buffer(AVCodecContext * ctx,AVFrame * av_frame,int flags)657 static int vs_video_get_buffer
658 (
659 AVCodecContext *ctx,
660 AVFrame *av_frame,
661 int flags
662 )
663 {
664 av_frame->opaque = NULL;
665 lw_video_output_handler_t *lw_vohp = (lw_video_output_handler_t *)ctx->opaque;
666 vs_video_output_handler_t *vs_vohp = (vs_video_output_handler_t *)lw_vohp->private_handler;
667 enum AVPixelFormat pix_fmt = av_frame->format;
668 avoid_yuv_scale_conversion( &pix_fmt );
669 av_frame->format = pix_fmt; /* Don't use AV_PIX_FMT_YUVJ*. */
670 if( (!vs_vohp->variable_info && lw_vohp->scaler.output_pixel_format != pix_fmt)
671 || !vs_check_dr_available( ctx, pix_fmt ) )
672 return avcodec_default_get_buffer2( ctx, av_frame, flags );
673 /* New VapourSynth video frame buffer. */
674 vs_video_buffer_handler_t *vs_vbhp = malloc( sizeof(vs_video_buffer_handler_t) );
675 if( !vs_vbhp )
676 {
677 av_frame_unref( av_frame );
678 return AVERROR( ENOMEM );
679 }
680 av_frame->opaque = vs_vbhp;
681 avcodec_align_dimensions2( ctx, &av_frame->width, &av_frame->height, av_frame->linesize );
682 VSFrameRef *vs_frame_buffer = new_output_video_frame( vs_vohp, av_frame, NULL, 0,
683 vs_vohp->frame_ctx, vs_vohp->core, vs_vohp->vsapi );
684 if( !vs_frame_buffer )
685 {
686 free( vs_vbhp );
687 av_frame_unref( av_frame );
688 return AVERROR( ENOMEM );
689 }
690 vs_vbhp->vs_frame_buffer = vs_frame_buffer;
691 vs_vbhp->vsapi = vs_vohp->vsapi;
692 /* Create frame buffers for the decoder.
693 * The callback vs_video_release_buffer_handler() shall be called when no reference to the video buffer handler is present.
694 * The callback vs_video_unref_buffer_handler() decrements the reference-counter by 1. */
695 memset( av_frame->buf, 0, sizeof(av_frame->buf) );
696 memset( av_frame->data, 0, sizeof(av_frame->data) );
697 memset( av_frame->linesize, 0, sizeof(av_frame->linesize) );
698 AVBufferRef *vs_buffer_handler = av_buffer_create( NULL, 0, vs_video_release_buffer_handler, vs_vbhp, 0 );
699 if( !vs_buffer_handler )
700 {
701 vs_video_release_buffer_handler( vs_vbhp, NULL );
702 av_frame_unref( av_frame );
703 return AVERROR( ENOMEM );
704 }
705 vs_vohp->component_reorder = get_component_reorder( pix_fmt );
706 for( int i = 0; i < 3; i++ )
707 if( vs_create_plane_buffer( vs_vbhp, vs_buffer_handler, av_frame, i, vs_vohp->component_reorder[i] ) < 0 )
708 goto fail;
709 /* Here, a variable 'vs_buffer_handler' itself is not referenced by any pointer. */
710 av_buffer_unref( &vs_buffer_handler );
711 av_frame->nb_extended_buf = 0;
712 av_frame->extended_data = av_frame->data;
713 return 0;
714 fail:
715 av_frame_unref( av_frame );
716 av_buffer_unref( &vs_buffer_handler );
717 return AVERROR( ENOMEM );
718 }
719
vs_setup_video_rendering(lw_video_output_handler_t * lw_vohp,AVCodecContext * ctx,VSVideoInfo * vi,VSMap * out,int width,int height)720 int vs_setup_video_rendering
721 (
722 lw_video_output_handler_t *lw_vohp,
723 AVCodecContext *ctx,
724 VSVideoInfo *vi,
725 VSMap *out,
726 int width,
727 int height
728 )
729 {
730 vs_video_output_handler_t *vs_vohp = (vs_video_output_handler_t *)lw_vohp->private_handler;
731 const VSAPI *vsapi = vs_vohp->vsapi;
732 enum AVPixelFormat output_pixel_format;
733 if( determine_colorspace_conversion( vs_vohp, ctx->pix_fmt, &output_pixel_format ) )
734 {
735 set_error_on_init( out, vsapi, "lsmas: %s is not supported", av_get_pix_fmt_name( ctx->pix_fmt ) );
736 return -1;
737 }
738 vs_vohp->direct_rendering &= vs_check_dr_available( ctx, ctx->pix_fmt );
739 int (*dr_get_buffer)( struct AVCodecContext *, AVFrame *, int ) = vs_vohp->direct_rendering ? vs_video_get_buffer : NULL;
740 setup_video_rendering( lw_vohp, SWS_FAST_BILINEAR,
741 width, height, output_pixel_format,
742 ctx, dr_get_buffer );
743 if( vs_vohp->variable_info )
744 {
745 vi->format = NULL;
746 vi->width = 0;
747 vi->height = 0;
748 /* Unused */
749 //lw_vohp->output_width = 0;
750 //lw_vohp->output_height = 0;
751 }
752 else
753 {
754 vi->format = vsapi->getFormatPreset( vs_vohp->vs_output_pixel_format, vs_vohp->core );
755 vi->width = lw_vohp->output_width;
756 vi->height = lw_vohp->output_height;
757 vs_vohp->background_frame = vsapi->newVideoFrame( vi->format, vi->width, vi->height, NULL, vs_vohp->core );
758 if( !vs_vohp->background_frame )
759 {
760 set_error_on_init( out, vsapi, "lsmas: failed to allocate memory for the background black frame data." );
761 return -1;
762 }
763 vs_vohp->make_black_background( vs_vohp->background_frame, vsapi );
764 }
765 return 0;
766 }
767
vs_free_video_output_handler(void * private_handler)768 static void vs_free_video_output_handler
769 (
770 void *private_handler
771 )
772 {
773 vs_video_output_handler_t *vs_vohp = (vs_video_output_handler_t *)private_handler;
774 if( !vs_vohp )
775 return;
776 if( vs_vohp->vsapi && vs_vohp->vsapi->freeFrame && vs_vohp->background_frame )
777 vs_vohp->vsapi->freeFrame( vs_vohp->background_frame );
778 lw_free( vs_vohp );
779 }
780
vs_allocate_video_output_handler(lw_video_output_handler_t * vohp)781 vs_video_output_handler_t *vs_allocate_video_output_handler
782 (
783 lw_video_output_handler_t *vohp
784 )
785 {
786 vs_video_output_handler_t *vs_vohp = lw_malloc_zero( sizeof(vs_video_output_handler_t) );
787 if( !vs_vohp )
788 return NULL;
789 vohp->private_handler = vs_vohp;
790 vohp->free_private_handler = vs_free_video_output_handler;
791 return vs_vohp;
792 }
793
vs_set_frame_properties(AVFrame * av_frame,int64_t duration_num,int64_t duration_den,VSFrameRef * vs_frame,const VSAPI * vsapi)794 void vs_set_frame_properties
795 (
796 AVFrame *av_frame,
797 int64_t duration_num,
798 int64_t duration_den,
799 VSFrameRef *vs_frame,
800 const VSAPI *vsapi
801 )
802 {
803 VSMap *props = vsapi->getFramePropsRW( vs_frame );
804 /* Sample aspect ratio */
805 vsapi->propSetInt( props, "_SARNum", av_frame->sample_aspect_ratio.num, paReplace );
806 vsapi->propSetInt( props, "_SARDen", av_frame->sample_aspect_ratio.den, paReplace );
807 /* Sample duration */
808 vsapi->propSetInt( props, "_DurationNum", duration_num, paReplace );
809 vsapi->propSetInt( props, "_DurationDen", duration_den, paReplace );
810 /* Color format
811 * The decoded color format may not match with the output. Set proper properties when
812 * no YUV->RGB conversion is there. */
813 const VSFormat *vs_format = vsapi->getFrameFormat( vs_frame );
814 if( vs_format->colorFamily != cmRGB )
815 {
816 if( av_frame->color_range != AVCOL_RANGE_UNSPECIFIED )
817 vsapi->propSetInt( props, "_ColorRange", av_frame->color_range == AVCOL_RANGE_MPEG, paReplace );
818 vsapi->propSetInt( props, "_Primaries", av_frame->color_primaries, paReplace );
819 vsapi->propSetInt( props, "_Transfer", av_frame->color_trc, paReplace );
820 vsapi->propSetInt( props, "_Matrix", av_frame->colorspace, paReplace );
821 if( av_frame->chroma_location > 0 )
822 vsapi->propSetInt( props, "_ChromaLocation", av_frame->chroma_location - 1, paReplace );
823 }
824 /* Picture type */
825 char pict_type = av_get_picture_type_char( av_frame->pict_type );
826 vsapi->propSetData( props, "_PictType", &pict_type, 1, paReplace );
827 /* BFF or TFF */
828 int field_based = 0;
829 if( av_frame->interlaced_frame )
830 field_based = av_frame->top_field_first ? 2 : 1;
831 vsapi->propSetInt( props, "_FieldBased", field_based, paReplace );
832 }
833