[vlc-commits] [Git][videolan/vlc][master] 3 commits: video_filter: replace cv::imwrite with picture_t write

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Jun 3 13:10:11 UTC 2026



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
51f2c043 by Brandon Li at 2026-06-03T11:27:21+00:00
video_filter: replace cv::imwrite with picture_t write

- - - - -
63077a1b by Brandon Li at 2026-06-03T11:27:21+00:00
contrib: compile opencv4 with function/data sections

- - - - -
e367fe5c by Brandon Li at 2026-06-03T11:27:21+00:00
buildsystem: enable dead code stripping at link time

- - - - -


6 changed files:

- configure.ac
- contrib/src/opencv4/rules.mak
- meson.build
- modules/video_filter/Makefile.am
- modules/video_filter/meson.build
- modules/video_filter/sam3.cpp


Changes:

=====================================
configure.ac
=====================================
@@ -492,6 +492,29 @@ case "${host_os}" in
     ;;
 esac
 
+dnl
+dnl Drops unused symbols.
+dnl ELF linkers use --gc-sections, while Mach-O uses -dead_strip.
+dnl
+AC_MSG_CHECKING([for linker dead-code stripping flag])
+GC_SECTIONS_LDFLAGS=""
+VLC_SAVE_FLAGS
+AX_APPEND_FLAG([-Wl,--gc-sections], [LDFLAGS])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
+    [GC_SECTIONS_LDFLAGS="-Wl,--gc-sections"], [])
+VLC_RESTORE_FLAGS
+AS_IF([test -z "${GC_SECTIONS_LDFLAGS}"], [
+    VLC_SAVE_FLAGS
+    AX_APPEND_FLAG([-Wl,-dead_strip], [LDFLAGS])
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
+        [GC_SECTIONS_LDFLAGS="-Wl,-dead_strip"], [])
+    VLC_RESTORE_FLAGS
+])
+AS_IF([test -n "${GC_SECTIONS_LDFLAGS}"],
+    [AC_MSG_RESULT([${GC_SECTIONS_LDFLAGS}])],
+    [AC_MSG_RESULT([none])])
+AC_SUBST([GC_SECTIONS_LDFLAGS])
+
 dnl WinRT
 AC_ARG_ENABLE([winstore_app],
      AS_HELP_STRING([--enable-winstore-app],


=====================================
contrib/src/opencv4/rules.mak
=====================================
@@ -37,6 +37,7 @@ opencv4: opencv-$(OPENCV4_VERSION).tar.gz .sum-opencv4
 
 # only enable necessary pkgs
 OPENCV4_ENV =
+
 OPENCV4_CONF := \
 	-DBUILD_LIST=core,imgproc,imgcodecs,objdetect \
 	-DOPENCV_GENERATE_PKGCONFIG=ON \
@@ -71,7 +72,10 @@ OPENCV4_CONF := \
 	-DBUILD_ZLIB=OFF \
 	-DBUILD_PNG=OFF \
 	-DBUILD_JPEG=OFF \
-	-DBUILD_ITT=OFF
+	-DBUILD_ITT=OFF \
+	-DOPENCV_FORCE_FUNCTIONS_SECTIONS=ON
+# OpenCV's adds -ffunction-sections/-fdata-sections by default, but skips for static
+# iOS/Android builds. Force it on
 
 # NEON mandatory on aarch64
 ifneq ($(findstring aarch64,$(HOST)),)


=====================================
meson.build
=====================================
@@ -927,6 +927,15 @@ if cc.has_link_argument('-Wl,-Bsymbolic')
     symbolic_linkargs += '-Wl,-Bsymbolic'
 endif
 
+# Drops unused symbols.
+# ELF linkers use --gc-sections, while Mach-O uses -dead_strip.
+gc_sections_linkargs = []
+if cc.has_link_argument('-Wl,--gc-sections')
+    gc_sections_linkargs += '-Wl,--gc-sections'
+elif cc.has_link_argument('-Wl,-dead_strip')
+    gc_sections_linkargs += '-Wl,-dead_strip'
+endif
+
 # Check for struct sockaddr_storage type
 # Define it to `sockaddr` if missing
 sockaddr_prefix = ['#include <sys/types.h>']


=====================================
modules/video_filter/Makefile.am
=====================================
@@ -127,7 +127,7 @@ video_filter_PLUGINS += \
 libsam3_plugin_la_SOURCES = video_filter/sam3.cpp
 libsam3_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENCV4_CFLAGS)
 libsam3_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) -fexceptions
-libsam3_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(video_filterdir)'
+libsam3_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(GC_SECTIONS_LDFLAGS) -rpath '$(video_filterdir)'
 libsam3_plugin_la_LIBADD = $(LIBM) $(OPENCV4_LIBS)
 EXTRA_LTLIBRARIES += libsam3_plugin.la
 video_filter_LTLIBRARIES += $(LTLIBsam3)
@@ -235,7 +235,7 @@ endif
 libopencv_wrapper_plugin_la_SOURCES = video_filter/opencv_wrapper.cpp
 libopencv_wrapper_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENCV_CFLAGS)
 libopencv_wrapper_plugin_la_LIBADD = $(OPENCV_LIBS)
-libopencv_wrapper_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(video_filter_RPATH)
+libopencv_wrapper_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(GC_SECTIONS_LDFLAGS) $(video_filter_RPATH)
 video_filter_PLUGINS += $(LTLIBopencv_wrapper)
 EXTRA_LTLIBRARIES += libopencv_wrapper_plugin.la
 
@@ -271,7 +271,7 @@ video_filter_PLUGINS += libblend_plugin.la
 libopencv_example_plugin_la_SOURCES = video_filter/opencv_example.cpp video_filter/filter_event_info.h
 libopencv_example_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENCV_CFLAGS)
 libopencv_example_plugin_la_LIBADD = $(OPENCV_LIBS)
-libopencv_example_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(video_filter_RPATH)
+libopencv_example_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(GC_SECTIONS_LDFLAGS) $(video_filter_RPATH)
 video_filter_PLUGINS += $(LTLIBopencv_example)
 EXTRA_LTLIBRARIES += libopencv_example_plugin.la
 


=====================================
modules/video_filter/meson.build
=====================================
@@ -419,6 +419,7 @@ vlc_modules += {
     'name' : 'opencv_wrapper',
     'sources' : files('opencv_wrapper.cpp'),
     'dependencies' : [m_lib, opencv_dep],
+    'link_args' : gc_sections_linkargs,
     'enabled' : opencv_dep.found()
 }
 
@@ -426,6 +427,7 @@ vlc_modules += {
     'name' : 'opencv_example',
     'sources' : files('opencv_example.cpp'),
     'dependencies' : [m_lib, opencv_dep],
+    'link_args' : gc_sections_linkargs,
     'enabled' : opencv_dep.found()
 }
 
@@ -441,6 +443,7 @@ if opencv_dep.found() and sam3_dep.found()
             opencv_dep,
             sam3_dep,
         ],
-        'cpp_args' : [ '-fexceptions' ]
+        'cpp_args' : [ '-fexceptions' ],
+        'link_args' : gc_sections_linkargs
     }
 endif
\ No newline at end of file


=====================================
modules/video_filter/sam3.cpp
=====================================
@@ -32,6 +32,7 @@
 #include <vlc_plugin.h>
 #include <vlc_filter.h>
 #include <vlc_picture.h>
+#include <vlc_block.h>
 #include <vlc_mouse.h>
 #include <vlc_fs.h>
 
@@ -142,6 +143,61 @@ vlc_module_begin( )
                N_ ( "Natural-language concept to segment" ) )
 vlc_module_end( )
 
+/*****************************************************************************
+* WriteMatAsImage: Encodes a Mat and writes to disk
+*****************************************************************************/
+static bool WriteMatAsImage( filter_t* p_filter, const cv::Mat& mat_bgr,
+                              const char* psz_path, vlc_fourcc_t i_codec )
+{
+    if ( mat_bgr.empty( ) || mat_bgr.type( ) != CV_8UC3 )
+    {
+        return false;
+    }
+
+    video_format_t fmt_in;
+    video_format_Init( &fmt_in, VLC_CODEC_BGR24 );
+    video_format_Setup( &fmt_in, VLC_CODEC_BGR24,
+                        mat_bgr.cols, mat_bgr.rows,
+                        mat_bgr.cols, mat_bgr.rows, 1, 1 );
+
+    picture_t* p_pic = picture_NewFromFormat( &fmt_in );
+    if ( !p_pic )
+    {
+        return false;
+    }
+
+    // copy planes
+    plane_t* p_plane = &p_pic->p[ 0 ];
+    const size_t i_row_bytes = static_cast<size_t>( mat_bgr.cols ) * 3;
+    for ( int y = 0; y < mat_bgr.rows; ++y )
+    {
+        memcpy( p_plane->p_pixels + y * p_plane->i_pitch,
+                mat_bgr.ptr( y ), i_row_bytes );
+    }
+
+    block_t* p_block = nullptr;
+    const int i_ret = picture_Export( VLC_OBJECT( p_filter ), &p_block, nullptr,
+                                       p_pic, i_codec, 0, 0, false );
+    picture_Release( p_pic );
+
+    if ( i_ret != VLC_SUCCESS || !p_block )
+    {
+        return false;
+    }
+
+    FILE* p_file = vlc_fopen( psz_path, "wb" );
+    bool b_ok = false;
+    if ( p_file )
+    {
+        const size_t i_written = fwrite( p_block->p_buffer, 1, p_block->i_buffer, p_file );
+        b_ok = ( i_written == p_block->i_buffer );
+        fclose( p_file );
+    }
+
+    block_Release( p_block );
+    return b_ok;
+}
+
 /*****************************************************************************
 * Export: Export a single mask to file
 *****************************************************************************/
@@ -168,28 +224,27 @@ static void Export( filter_t* p_filter, const segmented_object_t& obj, const cv:
     cv::resize( obj.mat_mask, mat_mask_scaled, mat_frame.size( ), 0, 0, cv::INTER_LINEAR );
     cv::threshold( mat_mask_scaled, mat_mask_scaled, 128, 255, cv::THRESH_BINARY );
 
-    // create file name
-    std::string str_filename = std::string( p_sys->psz_export_path ) + "/mask_" +
+    // export the original frame as a 3-channel PNG
+    std::string frame_filename = std::string( p_sys->psz_export_path ) + "/frame_" +
         psz_timestamp + "_id" + std::to_string( obj.i_id ) + ".png";
-
-    // export mask onto Mat - optimized version
-    std::vector<cv::Mat> vec_channels;
-    cv::split( mat_frame, vec_channels );
-    vec_channels.push_back( mat_mask_scaled );
-    cv::Mat mat_export;
-    cv::merge( vec_channels, mat_export );
-
-    // write image
-    if ( !cv::imwrite( str_filename, mat_export ) )
+    if ( !WriteMatAsImage( p_filter, mat_frame, frame_filename.c_str( ), VLC_CODEC_PNG ) )
     {
-        msg_Err( p_filter, "Failed to export mask to %s", str_filename.c_str( ) );
+        msg_Err( p_filter, "Failed to export frame to %s", frame_filename.c_str( ) );
         return;
     }
-    msg_Info( p_filter, "Exported mask %d to %s", obj.i_id, str_filename.c_str( ) );
+    msg_Info( p_filter, "Exported frame %d to %s", obj.i_id, frame_filename.c_str( ) );
 
-    // create file name
-    std::string vis_filename = std::string( p_sys->psz_export_path ) + "/visualization_" +
-        psz_timestamp + "_id" + std::to_string( obj.i_id ) + ".jpg";
+    // export the binary mask as a grayscale PNG
+    cv::Mat mat_mask_bgr;
+    cv::cvtColor( mat_mask_scaled, mat_mask_bgr, cv::COLOR_GRAY2BGR );
+    std::string mask_filename = std::string( p_sys->psz_export_path ) + "/mask_" +
+        psz_timestamp + "_id" + std::to_string( obj.i_id ) + ".png";
+    if ( !WriteMatAsImage( p_filter, mat_mask_bgr, mask_filename.c_str( ), VLC_CODEC_PNG ) )
+    {
+        msg_Err( p_filter, "Failed to export mask to %s", mask_filename.c_str( ) );
+        return;
+    }
+    msg_Info( p_filter, "Exported mask %d to %s", obj.i_id, mask_filename.c_str( ) );
 
     // clone image, add mask overlay
     cv::Mat mat_visualization = mat_frame.clone( );
@@ -215,8 +270,10 @@ static void Export( filter_t* p_filter, const segmented_object_t& obj, const cv:
     }
     cv::drawContours( mat_visualization, vec_scaled_contours, -1, obj.scalar_color, 2, cv::LINE_AA );
 
-    // write image
-    if ( !cv::imwrite( vis_filename, mat_visualization ) )
+    // export the visualization as JPEG
+    std::string vis_filename = std::string( p_sys->psz_export_path ) + "/visualization_" +
+        psz_timestamp + "_id" + std::to_string( obj.i_id ) + ".jpg";
+    if ( !WriteMatAsImage( p_filter, mat_visualization, vis_filename.c_str( ), VLC_CODEC_JPEG ) )
     {
         msg_Err( p_filter, "Failed to export visualization to %s", vis_filename.c_str( ) );
         return;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ca850d6979a333e8fe191532e46c078f4724facf...e367fe5c26b18dcd789a73061ec79680889b831c

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ca850d6979a333e8fe191532e46c078f4724facf...e367fe5c26b18dcd789a73061ec79680889b831c
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help




More information about the vlc-commits mailing list