@@ -74,6 +74,26 @@ static inline float f16_to_f32(uint16_t h)
7474 return f ;
7575}
7676
77+ static int mltofx_source_prefers_top_left_origin (const OfxPlugin * plugin ,
78+ const char * depth_format ,
79+ int is_source )
80+ {
81+ if (!plugin || !plugin -> pluginIdentifier || !depth_format )
82+ return 0 ;
83+
84+ // GMIC's byte-depth path expects top-left memory addressing for Source.
85+ if (is_source && !strncmp (plugin -> pluginIdentifier , "eu.gmic." , 8 )
86+ && !strcmp (depth_format , kOfxBitDepthByte )) {
87+ return 1 ;
88+ }
89+
90+ // NTSC-rs crashes without top-left addressing for Source, but only in the 16-bit path.
91+ if (!strncmp (plugin -> pluginIdentifier , "wtf.vala:NtscRs" , 15 )) {
92+ return strcmp (depth_format , kOfxBitDepthByte );
93+ }
94+ return 0 ;
95+ }
96+
7797uint16_t * mltofx_rgba64_to_half (const uint16_t * src , int n_pixels )
7898{
7999 int count = n_pixels * 4 ;
@@ -766,6 +786,92 @@ static OfxStatus paramGetPropertySet(OfxParamHandle param, OfxPropertySetHandle
766786 return kOfxStatOK ;
767787}
768788
789+ static void mltofx_initialize_param_value_from_default (mlt_properties param )
790+ {
791+ if (!param )
792+ return ;
793+
794+ char * param_type = mlt_properties_get (param , "t" );
795+ mlt_properties param_props = mlt_properties_get_properties (param , "p" );
796+ if (!param_type || !param_props )
797+ return ;
798+
799+ if (strcmp (param_type , kOfxParamTypeInteger ) == 0
800+ || strcmp (param_type , kOfxParamTypeBoolean ) == 0
801+ || strcmp (param_type , kOfxParamTypeInteger2D ) == 0
802+ || strcmp (param_type , kOfxParamTypeInteger3D ) == 0 ) {
803+ int count = 1 ;
804+ if (strcmp (param_type , kOfxParamTypeInteger2D ) == 0 )
805+ count = 2 ;
806+ else if (strcmp (param_type , kOfxParamTypeInteger3D ) == 0 )
807+ count = 3 ;
808+ for (int i = 0 ; i < count ; ++ i ) {
809+ int value = 0 ;
810+ if (propGetInt ((OfxPropertySetHandle ) param_props , kOfxParamPropDefault , i , & value )
811+ == kOfxStatOK ) {
812+ propSetInt ((OfxPropertySetHandle ) param_props , "MltOfxParamValue" , i , value );
813+ }
814+ }
815+ } else if (strcmp (param_type , kOfxParamTypeDouble ) == 0
816+ || strcmp (param_type , kOfxParamTypeDouble2D ) == 0
817+ || strcmp (param_type , kOfxParamTypeDouble3D ) == 0
818+ || strcmp (param_type , kOfxParamTypeRGB ) == 0
819+ || strcmp (param_type , kOfxParamTypeRGBA ) == 0 ) {
820+ int count = 1 ;
821+ if (strcmp (param_type , kOfxParamTypeDouble2D ) == 0 )
822+ count = 2 ;
823+ else if (strcmp (param_type , kOfxParamTypeDouble3D ) == 0
824+ || strcmp (param_type , kOfxParamTypeRGB ) == 0 )
825+ count = 3 ;
826+ else if (strcmp (param_type , kOfxParamTypeRGBA ) == 0 )
827+ count = 4 ;
828+ for (int i = 0 ; i < count ; ++ i ) {
829+ double value = 0.0 ;
830+ if (propGetDouble ((OfxPropertySetHandle ) param_props , kOfxParamPropDefault , i , & value )
831+ == kOfxStatOK ) {
832+ propSetDouble ((OfxPropertySetHandle ) param_props , "MltOfxParamValue" , i , value );
833+ }
834+ }
835+ } else if (strcmp (param_type , kOfxParamTypeString ) == 0
836+ || strcmp (param_type , kOfxParamTypeStrChoice ) == 0 ) {
837+ char * value = NULL ;
838+ if (propGetString ((OfxPropertySetHandle ) param_props , kOfxParamPropDefault , 0 , & value )
839+ == kOfxStatOK
840+ && value ) {
841+ propSetString ((OfxPropertySetHandle ) param_props , "MltOfxParamValue" , 0 , value );
842+ }
843+ } else if (strcmp (param_type , kOfxParamTypeChoice ) == 0 ) {
844+ int default_index = 0 ;
845+ if (propGetInt ((OfxPropertySetHandle ) param_props , kOfxParamPropDefault , 0 , & default_index )
846+ == kOfxStatOK ) {
847+ char * label = NULL ;
848+ if (propGetString ((OfxPropertySetHandle ) param_props ,
849+ kOfxParamPropChoiceOption ,
850+ default_index ,
851+ & label )
852+ == kOfxStatOK
853+ && label ) {
854+ propSetString ((OfxPropertySetHandle ) param_props , "MltOfxParamValue" , 0 , label );
855+ }
856+ }
857+ }
858+ }
859+
860+ static void mltofx_initialize_param_values (mlt_properties iparams )
861+ {
862+ if (!iparams )
863+ return ;
864+
865+ int count = mlt_properties_count (iparams );
866+ for (int i = 1 ; i < count ; ++ i ) {
867+ char * name = mlt_properties_get_name (iparams , i );
868+ if (!name )
869+ continue ;
870+ mlt_properties param = mlt_properties_get_properties (iparams , name );
871+ mltofx_initialize_param_value_from_default (param );
872+ }
873+ }
874+
769875static OfxStatus paramGetValueImpl (OfxParamHandle paramHandle , va_list ap )
770876{
771877 mlt_properties param = (mlt_properties ) paramHandle ;
@@ -780,7 +886,7 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
780886 if (status != kOfxStatOK ) {
781887 status = propGetInt ((OfxPropertySetHandle ) param_props , "OfxParamPropDefault" , 0 , value );
782888 if (status != kOfxStatOK )
783- return kOfxStatErrUnknown ;
889+ * value = 0 ;
784890 }
785891 } else if (strcmp (param_type , kOfxParamTypeChoice ) == 0 ) {
786892 // MltOfxParamValue stores the string label; convert to integer index for the OFX plugin.
@@ -810,12 +916,12 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
810916 0 ,
811917 value );
812918 if (status != kOfxStatOK )
813- return kOfxStatErrUnknown ;
919+ * value = 0 ;
814920 }
815921 } else {
816922 status = propGetInt ((OfxPropertySetHandle ) param_props , "OfxParamPropDefault" , 0 , value );
817923 if (status != kOfxStatOK )
818- return kOfxStatErrUnknown ;
924+ * value = 0 ;
819925 }
820926 } else if (strcmp (param_type , kOfxParamTypeDouble ) == 0 ) {
821927 double * value = va_arg (ap , double * );
@@ -827,7 +933,7 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
827933 0 ,
828934 value );
829935 if (status != kOfxStatOK )
830- return kOfxStatErrUnknown ;
936+ * value = 0.0 ;
831937 }
832938 } else if (strcmp (param_type , kOfxParamTypeString ) == 0
833939 || strcmp (param_type , kOfxParamTypeStrChoice ) == 0 ) {
@@ -840,7 +946,7 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
840946 0 ,
841947 value );
842948 if (status != kOfxStatOK )
843- return kOfxStatErrUnknown ;
949+ * value = "" ;
844950 }
845951 } else if (strcmp (param_type , kOfxParamTypeRGBA ) == 0 ) {
846952 double * red = va_arg (ap , double * );
@@ -875,8 +981,12 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
875981 "OfxParamPropDefault" ,
876982 3 ,
877983 alpha );
878- if (status != kOfxStatOK )
879- return kOfxStatErrUnknown ;
984+ if (status != kOfxStatOK ) {
985+ * red = 0.0 ;
986+ * green = 0.0 ;
987+ * blue = 0.0 ;
988+ * alpha = 1.0 ;
989+ }
880990 }
881991 } else if (strcmp (param_type , kOfxParamTypeRGB ) == 0 ) {
882992 double * red = va_arg (ap , double * );
@@ -903,8 +1013,11 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
9031013 "OfxParamPropDefault" ,
9041014 2 ,
9051015 blue );
906- if (status != kOfxStatOK )
907- return kOfxStatErrUnknown ;
1016+ if (status != kOfxStatOK ) {
1017+ * red = 0.0 ;
1018+ * green = 0.0 ;
1019+ * blue = 0.0 ;
1020+ }
9081021 }
9091022 } else if (strcmp (param_type , kOfxParamTypeDouble2D ) == 0 ) {
9101023 double * X = va_arg (ap , double * );
@@ -922,8 +1035,10 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
9221035 "OfxParamPropDefault" ,
9231036 1 ,
9241037 Y );
925- if (status != kOfxStatOK )
926- return kOfxStatErrUnknown ;
1038+ if (status != kOfxStatOK ) {
1039+ * X = 0.0 ;
1040+ * Y = 0.0 ;
1041+ }
9271042 }
9281043 } else if (strcmp (param_type , kOfxParamTypeInteger2D ) == 0 ) {
9291044 int * X = va_arg (ap , int * );
@@ -937,8 +1052,10 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
9371052 status = propGetInt ((OfxPropertySetHandle ) param_props , "OfxParamPropDefault" , 0 , X );
9381053 if (status == kOfxStatOK )
9391054 status = propGetInt ((OfxPropertySetHandle ) param_props , "OfxParamPropDefault" , 1 , Y );
940- if (status != kOfxStatOK )
941- return kOfxStatErrUnknown ;
1055+ if (status != kOfxStatOK ) {
1056+ * X = 0 ;
1057+ * Y = 0 ;
1058+ }
9421059 }
9431060 } else if (strcmp (param_type , kOfxParamTypeDouble3D ) == 0 ) {
9441061 double * X = va_arg (ap , double * );
@@ -964,8 +1081,11 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
9641081 "OfxParamPropDefault" ,
9651082 2 ,
9661083 Z );
967- if (status != kOfxStatOK )
968- return kOfxStatErrUnknown ;
1084+ if (status != kOfxStatOK ) {
1085+ * X = 0.0 ;
1086+ * Y = 0.0 ;
1087+ * Z = 0.0 ;
1088+ }
9691089 }
9701090 } else if (strcmp (param_type , kOfxParamTypeInteger3D ) == 0 ) {
9711091 int * X = va_arg (ap , int * );
@@ -984,8 +1104,11 @@ static OfxStatus paramGetValueImpl(OfxParamHandle paramHandle, va_list ap)
9841104 status = propGetInt ((OfxPropertySetHandle ) param_props , "OfxParamPropDefault" , 1 , Y );
9851105 if (status == kOfxStatOK )
9861106 status = propGetInt ((OfxPropertySetHandle ) param_props , "OfxParamPropDefault" , 2 , Z );
987- if (status != kOfxStatOK )
988- return kOfxStatErrUnknown ;
1107+ if (status != kOfxStatOK ) {
1108+ * X = 0 ;
1109+ * Y = 0 ;
1110+ * Z = 0 ;
1111+ }
9891112 }
9901113 }
9911114
@@ -2095,6 +2218,53 @@ static void mltofx_apply_cached_clip_preferences(mlt_properties image_effect)
20952218 mltofx_apply_clip_preferences (image_effect , pref_args );
20962219}
20972220
2221+ static void mltofx_set_mask_clip_disconnected (mlt_properties image_effect )
2222+ {
2223+ if (!image_effect )
2224+ return ;
2225+
2226+ mlt_properties mask_clip = NULL ;
2227+ mlt_properties mask_clip_props = NULL ;
2228+ clipGetHandle ((OfxImageEffectHandle ) image_effect ,
2229+ "Mask" ,
2230+ (OfxImageClipHandle * ) & mask_clip ,
2231+ (OfxPropertySetHandle * ) & mask_clip_props );
2232+ if (!mask_clip_props )
2233+ return ;
2234+
2235+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImageClipPropConnected , 0 , 0 );
2236+ propSetString ((OfxPropertySetHandle ) mask_clip_props ,
2237+ kOfxImageEffectPropComponents ,
2238+ 0 ,
2239+ kOfxImageComponentNone );
2240+ propSetString ((OfxPropertySetHandle ) mask_clip_props ,
2241+ kOfxImageClipPropUnmappedComponents ,
2242+ 0 ,
2243+ kOfxImageComponentNone );
2244+ propSetString ((OfxPropertySetHandle ) mask_clip_props ,
2245+ kOfxImageEffectPropPixelDepth ,
2246+ 0 ,
2247+ kOfxBitDepthNone );
2248+ propSetString ((OfxPropertySetHandle ) mask_clip_props ,
2249+ kOfxImageClipPropUnmappedPixelDepth ,
2250+ 0 ,
2251+ kOfxBitDepthNone );
2252+ propSetDouble ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropPixelAspectRatio , 0 , 1.0 );
2253+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropBounds , 0 , 0 );
2254+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropBounds , 1 , 0 );
2255+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropBounds , 2 , 0 );
2256+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropBounds , 3 , 0 );
2257+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropRegionOfDefinition , 0 , 0 );
2258+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropRegionOfDefinition , 1 , 0 );
2259+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropRegionOfDefinition , 2 , 0 );
2260+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImagePropRegionOfDefinition , 3 , 0 );
2261+ propSetInt ((OfxPropertySetHandle ) mask_clip_props , kOfxImageEffectPropRenderQualityDraft , 0 , 0 );
2262+ propSetInt ((OfxPropertySetHandle ) mask_clip_props ,
2263+ "uk.co.thefoundry.OfxImageEffectPropView" ,
2264+ 0 ,
2265+ 0 );
2266+ }
2267+
20982268const void * MltOfxfetchSuite (OfxPropertySetHandle host , const char * suiteName , int suiteVersion )
20992269{
21002270 mlt_log_debug (NULL , "[openfx] fetchSuite: `%s` v%d\n" , suiteName , suiteVersion );
@@ -2366,8 +2536,8 @@ void mltofx_set_source_clip_data(OfxPlugin *plugin,
23662536
23672537 int row_bytes = width * depth_byte_size ;
23682538 uint8_t * image_origin = image ;
2369- int gmic = ! strncmp (plugin -> pluginIdentifier , "eu.gmic." , 8 );
2370- if (!gmic && !top_left_origin && row_bytes > 0 && height > 0 ) {
2539+ int top_left_compat = mltofx_source_prefers_top_left_origin (plugin , depth_format , 1 );
2540+ if (!top_left_compat && !top_left_origin && row_bytes > 0 && height > 0 ) {
23712541 // OFX CPU images are addressed from lower-left. Point data at the
23722542 // first byte of the last scanline and use negative row bytes.
23732543 image_origin = image + ((size_t ) (height - 1 ) * (size_t ) row_bytes );
@@ -2466,6 +2636,8 @@ void mltofx_set_source_clip_data(OfxPlugin *plugin,
24662636
24672637 propSetInt ((OfxPropertySetHandle ) clip_prop , kOfxImageClipPropConnected , 0 , 1 );
24682638
2639+ mltofx_set_mask_clip_disconnected (image_effect );
2640+
24692641 // Preserve plugin-selected clip preferences across clip data refreshes.
24702642 mltofx_apply_cached_clip_preferences (image_effect );
24712643}
@@ -2512,7 +2684,8 @@ void mltofx_set_output_clip_data(OfxPlugin *plugin,
25122684
25132685 int row_bytes = width * depth_byte_size ;
25142686 uint8_t * image_origin = image ;
2515- if (!top_left_origin && row_bytes > 0 && height > 0 ) {
2687+ int top_left_compat = mltofx_source_prefers_top_left_origin (plugin , depth_format , 0 );
2688+ if (!top_left_compat && !top_left_origin && row_bytes > 0 && height > 0 ) {
25162689 // OFX CPU images are addressed from lower-left. Point data at the
25172690 // first byte of the last scanline and use negative row bytes.
25182691 image_origin = image + ((size_t ) (height - 1 ) * (size_t ) row_bytes );
@@ -2608,6 +2781,10 @@ void mltofx_set_output_clip_data(OfxPlugin *plugin,
26082781 0 ,
26092782 pixel_aspect_ratio );
26102783
2784+ propSetInt ((OfxPropertySetHandle ) clip_prop , kOfxImageClipPropConnected , 0 , 1 );
2785+
2786+ mltofx_set_mask_clip_disconnected (image_effect );
2787+
26112788 // Preserve plugin-selected clip preferences across clip data refreshes.
26122789 mltofx_apply_cached_clip_preferences (image_effect );
26132790}
@@ -2774,6 +2951,8 @@ void *mltofx_fetch_params(OfxPlugin *plugin, mlt_properties params, mlt_properti
27742951 propSetString ((OfxPropertySetHandle ) clip_props , kOfxImagePropField , 0 , kOfxImageFieldNone );
27752952 }
27762953
2954+ mltofx_set_mask_clip_disconnected (image_effect );
2955+
27772956 clip = NULL , clip_props = NULL ;
27782957 clipGetHandle ((OfxImageEffectHandle ) image_effect ,
27792958 "Output" ,
@@ -3092,6 +3271,10 @@ void *mltofx_fetch_params(OfxPlugin *plugin, mlt_properties params, mlt_properti
30923271 }
30933272 }
30943273
3274+ // Seed runtime param values from OFX defaults so plugins read stable values
3275+ // even when the user has not overridden a parameter.
3276+ mltofx_initialize_param_values (iparams );
3277+
30953278 mlt_properties_close (clips );
30963279 mlt_properties_close (iparams );
30973280 mlt_properties_close (props );
0 commit comments