@@ -127,6 +127,16 @@ struct upipe_ffmt {
127127
128128 /** swscale flags */
129129 int sws_flags ;
130+ /** deinterlace_vaapi mode option */
131+ const char * deinterlace_vaapi_mode ;
132+ /** scale_vaapi mode option */
133+ const char * scale_vaapi_mode ;
134+ /** vpp_qsv deinterlace option */
135+ const char * vpp_qsv_deinterlace ;
136+ /** vpp_qsv scale_mode option */
137+ const char * vpp_qsv_scale_mode ;
138+ /** ni_quadra_scale filterblit option */
139+ const char * ni_quadra_scale_filterblit ;
130140
131141 /** avfilter hw config type */
132142 char * hw_type ;
@@ -208,6 +218,11 @@ static struct upipe *upipe_ffmt_alloc(struct upipe_mgr *mgr,
208218 upipe_ffmt -> flow_def_wanted = flow_def ;
209219 upipe_ffmt -> flow_def_requested = NULL ;
210220 upipe_ffmt -> sws_flags = 0 ;
221+ upipe_ffmt -> deinterlace_vaapi_mode = NULL ;
222+ upipe_ffmt -> scale_vaapi_mode = NULL ;
223+ upipe_ffmt -> vpp_qsv_deinterlace = NULL ;
224+ upipe_ffmt -> vpp_qsv_scale_mode = NULL ;
225+ upipe_ffmt -> ni_quadra_scale_filterblit = NULL ;
211226 upipe_ffmt -> hw_type = NULL ;
212227 upipe_ffmt -> hw_device = NULL ;
213228 upipe_throw_ready (upipe );
@@ -376,16 +391,30 @@ static int upipe_ffmt_check_flow_format(struct upipe *upipe,
376391 bool pic_vaapi_out = !strcmp (surface_type_out , "av.vaapi" );
377392 bool pic_qsv_in = !strcmp (surface_type_in , "av.qsv" );
378393 bool pic_qsv_out = !strcmp (surface_type_out , "av.qsv" );
379- bool hw_in = pic_vaapi_in || pic_qsv_in ;
380- bool hw_out = pic_vaapi_out || pic_qsv_out ;
394+ bool pic_quadra_in = !strcmp (surface_type_in , "av.ni_quadra" );
395+ bool pic_quadra_out = !strcmp (surface_type_out , "av.ni_quadra" );
396+ bool hw_in = pic_vaapi_in || pic_qsv_in || pic_quadra_in ;
397+ bool hw_out = pic_vaapi_out || pic_qsv_out || pic_quadra_out ;
381398 bool hw = hw_in || hw_out ;
399+ int bit_depth_in = 0 ;
400+ int bit_depth_out = 0 ;
401+ uref_pic_flow_get_bit_depth (flow_def , & bit_depth_in );
402+ uref_pic_flow_get_bit_depth (flow_def_dup , & bit_depth_out );
382403 bool need_hw_transfer = (hw_in && !hw_out ) || (!hw_in && hw_out );
383404 bool need_derive = pic_vaapi_in && pic_qsv_out ;
405+ bool need_tonemap = ubase_check (uref_pic_flow_check_hdr10 (flow_def )) &&
406+ ubase_check (uref_pic_flow_check_sdr (flow_def_dup ));
384407 bool need_avfilter = ffmt_mgr -> avfilter_mgr && hw &&
385408 (need_deint || need_scale || need_format || need_hw_transfer ||
386409 need_derive || need_range );
387410
388411 if (need_avfilter ) {
412+ const char * range_in =
413+ ubase_check (uref_pic_flow_get_full_range (flow_def )) ?
414+ "full" : "limited" ;
415+ const char * range_out =
416+ ubase_check (uref_pic_flow_get_full_range (flow_def_dup )) ?
417+ "full" : "limited" ;
389418 if (need_format ) {
390419 const char * pix_fmt_in = "unknown" ;
391420 const char * pix_fmt_out = "unknown" ;
@@ -414,18 +443,15 @@ static int upipe_ffmt_check_flow_format(struct upipe *upipe,
414443 " → %" PRIu64 "x%" PRIu64 ,
415444 hsize_in , vsize_in , hsize_out , vsize_out );
416445 }
417- if (need_range ) {
418- const char * from =
419- ubase_check (uref_pic_flow_get_full_range (flow_def )) ?
420- "full" : "limited" ;
421- const char * to =
422- ubase_check (uref_pic_flow_get_full_range (flow_def_dup )) ?
423- "full" : "limited" ;
446+ if (need_range )
424447 upipe_notice_va (upipe , "need range conversion %s → %s" ,
425- from , to );
426- }
448+ range_in , range_out );
427449 if (need_derive )
428450 upipe_notice (upipe , "need hw surface mapping vaapi → qsv" );
451+ if (need_deint )
452+ upipe_notice (upipe , "need deinterlace" );
453+ if (need_tonemap )
454+ upipe_notice (upipe , "need tonemap hdr10 → sdr" );
429455
430456 uint64_t hsize = 0 , vsize = 0 ;
431457 uref_pic_flow_get_hsize (flow_def_dup , & hsize );
@@ -438,43 +464,160 @@ static int upipe_ffmt_check_flow_format(struct upipe *upipe,
438464 upipe_avfilt_mgr_get_pixfmt_name (ffmt_mgr -> avfilter_mgr ,
439465 flow_def_dup , & pix_fmt_sw , true);
440466
467+ int val ;
468+
469+ const char * color_matrix = NULL ;
470+ UBASE_RETURN (uref_pic_flow_get_matrix_coefficients_val (
471+ flow_def_dup , & val ))
472+ if (val != 2 )
473+ UBASE_RETURN (upipe_avfilt_mgr_get_color_space_name (
474+ ffmt_mgr -> avfilter_mgr , val , & color_matrix ))
475+
476+ const char * color_primaries = NULL ;
477+ UBASE_RETURN (uref_pic_flow_get_colour_primaries_val (
478+ flow_def_dup , & val ))
479+ if (val != 2 )
480+ UBASE_RETURN (upipe_avfilt_mgr_get_color_primaries_name (
481+ ffmt_mgr -> avfilter_mgr , val , & color_primaries ))
482+
483+ const char * color_transfer = NULL ;
484+ UBASE_RETURN (uref_pic_flow_get_transfer_characteristics_val (
485+ flow_def_dup , & val ))
486+ if (val != 2 )
487+ UBASE_RETURN (upipe_avfilt_mgr_get_color_transfer_name (
488+ ffmt_mgr -> avfilter_mgr , val , & color_transfer ))
489+
490+ bool in_10bit = bit_depth_in == 10 ;
491+ bool out_10bit = bit_depth_out == 10 ;
492+ const char * pix_fmt_semiplanar_in = in_10bit ? "p010le" : "nv12" ;
493+ const char * pix_fmt_semiplanar_out = out_10bit ? "p010le" : "nv12" ;
494+
441495 char filters [512 ];
442496 int pos = 0 ;
443-
444- #define str_cat (fmt , ...) pos += sprintf(filters + pos, fmt, ##__VA_ARGS__)
445-
446- if (!hw_in )
447- str_cat ("scale,format=nv12,hwupload," );
448- if (need_deint )
449- str_cat ("deinterlace_vaapi=auto=1," );
450- if (need_scale || need_format || need_range ) {
451- str_cat ("scale_vaapi=" );
452- if (need_scale )
453- str_cat ("w=%" PRIu64 ":h=%" PRIu64 , hsize , vsize );
454- if (need_format ) {
455- if (need_scale )
456- str_cat (":" );
457- str_cat ("format=%s" , pix_fmt_sw );
497+ int opt ;
498+
499+ #define add_filter (Name ) \
500+ pos += (opt = 0, snprintf(filters + pos, sizeof(filters) - pos, \
501+ "%s%s", pos ? "," : "", Name))
502+
503+ #define add_option (Fmt , ...) \
504+ pos += snprintf(filters + pos, sizeof(filters) - pos, \
505+ "%s" Fmt, opt++ ? ":" : "=", ##__VA_ARGS__)
506+
507+ if (!hw_in ) {
508+ if (pic_quadra_out ) {
509+ if (need_deint ) {
510+ add_filter ("yadif" );
511+ add_option ("deint=interlaced" );
512+ }
513+ } else {
514+ add_filter ("scale" );
515+ add_option ("interl=-1" );
516+ add_filter ("format" );
517+ add_option ("%s" , pix_fmt_semiplanar_in );
518+ }
519+ add_filter ("hwupload" );
520+ }
521+ if (pic_qsv_in || pic_qsv_out ) {
522+ if (pic_vaapi_in ) {
523+ add_filter ("hwmap" );
524+ add_option ("derive_device=qsv" );
525+ add_filter ("format" );
526+ add_option ("qsv" );
527+ }
528+ add_filter ("vpp_qsv" );
529+ if (need_deint )
530+ add_option ("deinterlace=%s" ,
531+ upipe_ffmt -> vpp_qsv_deinterlace ?: "advanced" );
532+ if (need_scale ) {
533+ add_option ("width=%" PRIu64 , hsize );
534+ add_option ("height=%" PRIu64 , vsize );
535+ }
536+ add_option ("scale_mode=%s" ,
537+ upipe_ffmt -> vpp_qsv_scale_mode ?: "hq" );
538+ if (need_format )
539+ add_option ("format=%s" , pix_fmt_sw );
540+ if (need_range )
541+ add_option ("out_range=%s" , range_out );
542+ if (color_matrix )
543+ add_option ("out_color_matrix=%s" , color_matrix );
544+ if (color_primaries )
545+ add_option ("out_color_primaries=%s" , color_primaries );
546+ if (color_transfer )
547+ add_option ("out_color_transfer=%s" , color_transfer );
548+ add_option ("tonemap=%d" , need_tonemap ? 1 : 0 );
549+ add_option ("async_depth=0" );
550+ } else {
551+ if (need_deint && !pic_quadra_out ) {
552+ add_filter ("deinterlace_vaapi" );
553+ add_option ("auto=1" );
554+ if (upipe_ffmt -> deinterlace_vaapi_mode )
555+ add_option ("mode=%s" ,
556+ upipe_ffmt -> deinterlace_vaapi_mode );
458557 }
459- if (need_range ) {
460- if (need_scale || need_format )
461- str_cat (":" );
462- str_cat ("out_range=%s" ,
463- ubase_check (uref_pic_flow_get_full_range (flow_def_dup )) ?
464- "full" : "limited" );
558+ if (need_scale || need_format || need_range ) {
559+ if (pic_quadra_out ) {
560+ add_filter ("ni_quadra_scale" );
561+ if (need_scale )
562+ add_option ("size=%" PRIu64 "x%" PRIu64 , hsize , vsize );
563+ if (upipe_ffmt -> ni_quadra_scale_filterblit )
564+ add_option ("filterblit=%s" ,
565+ upipe_ffmt -> ni_quadra_scale_filterblit );
566+ else
567+ add_option ("autoselect=1" );
568+ } else {
569+ add_filter ("scale_vaapi" );
570+ add_option ("mode=%s" ,
571+ upipe_ffmt -> scale_vaapi_mode ?: "hq" );
572+ if (need_scale ) {
573+ add_option ("w=%" PRIu64 , hsize );
574+ add_option ("h=%" PRIu64 , vsize );
575+ }
576+ if (need_range )
577+ add_option ("out_range=%s" , range_out );
578+ if (color_primaries )
579+ add_option ("out_color_primaries=%s" ,
580+ color_primaries );
581+ if (color_transfer )
582+ add_option ("out_color_transfer=%s" ,
583+ color_transfer );
584+ }
585+ if (color_matrix )
586+ add_option ("out_color_matrix=%s" , color_matrix );
587+ if (need_format )
588+ add_option ("format=%s" , pix_fmt_sw );
589+ }
590+ if (need_tonemap && (pic_vaapi_in || pic_vaapi_out )) {
591+ add_filter ("tonemap_vaapi" );
592+ add_option ("format=%s" , pix_fmt_sw );
593+ if (color_matrix )
594+ add_option ("matrix=%s" , color_matrix );
595+ if (color_primaries )
596+ add_option ("primaries=%s" , color_primaries );
597+ if (color_transfer )
598+ add_option ("transfer=%s" , color_transfer );
465599 }
466- str_cat ("," );
467600 }
468601 if (!hw_out ) {
469- str_cat ("hwmap=mode=read+direct,format=nv12," );
470- if (pix_fmt != NULL && strcmp (pix_fmt , "nv12" ))
471- str_cat ("scale,format=%s," , pix_fmt );
472- } else if (pic_qsv_out && (need_deint || need_scale || pic_vaapi_in ))
473- str_cat ("hwmap=derive_device=qsv,format=qsv" );
474- #undef str_cat
602+ add_filter ("hwmap" );
603+ add_option ("mode=read+direct" );
604+ add_filter ("format" );
605+ add_option ("%s" , pix_fmt_semiplanar_out );
606+ if (pix_fmt != NULL && strcmp (pix_fmt , pix_fmt_semiplanar_out )) {
607+ add_filter ("scale" );
608+ add_option ("interl=-1" );
609+ add_filter ("format" );
610+ add_option ("%s" , pix_fmt );
611+ }
612+ }
475613
476- if (filters [pos - 1 ] == ',' )
477- filters [pos - 1 ] = '\0' ;
614+ #undef add_filter
615+ #undef add_option
616+
617+ if (pos >= sizeof (filters )) {
618+ upipe_err (upipe , "filtergraph too long" );
619+ return UBASE_ERR_INVALID ;
620+ }
478621
479622 struct upipe * avfilt = upipe_void_alloc (
480623 ffmt_mgr -> avfilter_mgr ,
@@ -627,6 +770,60 @@ static int upipe_ffmt_check_flow_format(struct upipe *upipe,
627770 return err ;
628771}
629772
773+ /** @internal @This sets the filters options.
774+ *
775+ * @param upipe description structure of the pipe
776+ * @param option option name (filter name/option)
777+ * @param value value or NULL to use the default value
778+ * @return an error code
779+ */
780+ static int upipe_ffmt_set_option (struct upipe * upipe ,
781+ const char * option ,
782+ const char * value )
783+ {
784+ struct upipe_ffmt * upipe_ffmt = upipe_ffmt_from_upipe (upipe );
785+
786+ if (!strcmp (option , "deinterlace_vaapi/mode" ))
787+ // default bob weave motion_adaptive motion_compensated
788+ upipe_ffmt -> deinterlace_vaapi_mode = value ;
789+ else if (!strcmp (option , "scale_vaapi/mode" ))
790+ // default fast hq nl_anamorphic
791+ upipe_ffmt -> scale_vaapi_mode = value ;
792+ else if (!strcmp (option , "vpp_qsv/deinterlace" ))
793+ // bob advanced
794+ upipe_ffmt -> vpp_qsv_deinterlace = value ;
795+ else if (!strcmp (option , "vpp_qsv/scale_mode" ))
796+ // auto low_power hq compute vd ve
797+ upipe_ffmt -> vpp_qsv_scale_mode = value ;
798+ else if (!strcmp (option , "ni_quadra_scale/filterblit" ))
799+ // 0 1 2
800+ upipe_ffmt -> ni_quadra_scale_filterblit = value ;
801+ else if (!strcmp (option , "deinterlace-preset" )) {
802+ if (!strcmp (value , "fast" )) {
803+ upipe_ffmt -> deinterlace_vaapi_mode = "bob" ;
804+ upipe_ffmt -> vpp_qsv_deinterlace = "bob" ;
805+ } else if (!strcmp (value , "hq" )) {
806+ upipe_ffmt -> deinterlace_vaapi_mode = "motion_compensated" ;
807+ upipe_ffmt -> vpp_qsv_deinterlace = "advanced" ;
808+ } else
809+ return UBASE_ERR_INVALID ;
810+ } else if (!strcmp (option , "scale-preset" )) {
811+ if (!strcmp (value , "fast" )) {
812+ upipe_ffmt -> scale_vaapi_mode = "fast" ;
813+ upipe_ffmt -> vpp_qsv_scale_mode = "low_power" ;
814+ upipe_ffmt -> ni_quadra_scale_filterblit = "0" ;
815+ } else if (!strcmp (value , "hq" )) {
816+ upipe_ffmt -> scale_vaapi_mode = "hq" ;
817+ upipe_ffmt -> vpp_qsv_scale_mode = "hq" ;
818+ upipe_ffmt -> ni_quadra_scale_filterblit = NULL ;
819+ } else
820+ return UBASE_ERR_INVALID ;
821+ } else
822+ return UBASE_ERR_INVALID ;
823+
824+ return UBASE_ERR_NONE ;
825+ }
826+
630827/** @internal @This sets the input flow definition.
631828 *
632829 * @param upipe description structure of the pipe
@@ -784,6 +981,11 @@ static int upipe_ffmt_control(struct upipe *upipe, int command, va_list args)
784981 break ;
785982 }
786983
984+ case UPIPE_SET_OPTION : {
985+ const char * option = va_arg (args , const char * );
986+ const char * value = va_arg (args , const char * );
987+ return upipe_ffmt_set_option (upipe , option , value );
988+ }
787989 case UPIPE_SET_FLOW_DEF : {
788990 struct uref * flow_def = va_arg (args , struct uref * );
789991 return upipe_ffmt_set_flow_def (upipe , flow_def );
0 commit comments