videoio: plugins API versioning
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Fri, 4 Dec 2020 03:18:16 +0000 (03:18 +0000)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sun, 6 Dec 2020 16:19:13 +0000 (16:19 +0000)
modules/videoio/src/backend_plugin.cpp
modules/videoio/src/cap_ffmpeg.cpp
modules/videoio/src/cap_gstreamer.cpp
modules/videoio/src/cap_mfx_plugin.cpp
modules/videoio/src/cap_msmf.cpp
modules/videoio/src/cap_ueye.cpp
modules/videoio/src/plugin_api.hpp

index 40791efb012334e444c34bb6cf63733479ff8023..a37cb872c1f512c34385d776f7b441fffe562367 100644 (file)
@@ -224,7 +224,7 @@ public:
                 return;
             }
 #ifdef HAVE_FFMPEG_WRAPPER
-            if (plugin_api_->captureAPI == CAP_FFMPEG)
+            if (plugin_api_->v0.captureAPI == CAP_FFMPEG)
             {
                 // no checks for OpenCV minor version
             }
@@ -409,11 +409,11 @@ void PluginBackendFactory::loadPlugin()
             Ptr<PluginBackend> pluginBackend = makePtr<PluginBackend>(lib);
             if (pluginBackend && pluginBackend->plugin_api_)
             {
-                if (pluginBackend->plugin_api_->captureAPI != id_)
+                if (pluginBackend->plugin_api_->v0.captureAPI != id_)
                 {
                     CV_LOG_ERROR(NULL, "Video I/O: plugin '" << pluginBackend->plugin_api_->api_header.api_description <<
                                        "': unexpected backend ID: " <<
-                                       pluginBackend->plugin_api_->captureAPI << " vs " << (int)id_ << " (expected)");
+                                       pluginBackend->plugin_api_->v0.captureAPI << " vs " << (int)id_ << " (expected)");
                 }
                 else
                 {
@@ -444,10 +444,10 @@ public:
     {
         CV_Assert(plugin_api);
         CvPluginCapture capture = NULL;
-        if (plugin_api->Capture_open)
+        if (plugin_api->v0.Capture_open)
         {
-            CV_Assert(plugin_api->Capture_release);
-            if (CV_ERROR_OK == plugin_api->Capture_open(filename.empty() ? 0 : filename.c_str(), camera, &capture))
+            CV_Assert(plugin_api->v0.Capture_release);
+            if (CV_ERROR_OK == plugin_api->v0.Capture_open(filename.empty() ? 0 : filename.c_str(), camera, &capture))
             {
                 CV_Assert(capture);
                 return makePtr<PluginCapture>(plugin_api, capture);
@@ -464,30 +464,30 @@ public:
 
     ~PluginCapture()
     {
-        CV_DbgAssert(plugin_api_->Capture_release);
-        if (CV_ERROR_OK != plugin_api_->Capture_release(capture_))
+        CV_DbgAssert(plugin_api_->v0.Capture_release);
+        if (CV_ERROR_OK != plugin_api_->v0.Capture_release(capture_))
             CV_LOG_ERROR(NULL, "Video I/O: Can't release capture by plugin '" << plugin_api_->api_header.api_description << "'");
         capture_ = NULL;
     }
     double getProperty(int prop) const CV_OVERRIDE
     {
         double val = -1;
-        if (plugin_api_->Capture_getProperty)
-            if (CV_ERROR_OK != plugin_api_->Capture_getProperty(capture_, prop, &val))
+        if (plugin_api_->v0.Capture_getProperty)
+            if (CV_ERROR_OK != plugin_api_->v0.Capture_getProperty(capture_, prop, &val))
                 val = -1;
         return val;
     }
     bool setProperty(int prop, double val) CV_OVERRIDE
     {
-        if (plugin_api_->Capture_setProperty)
-            if (CV_ERROR_OK == plugin_api_->Capture_setProperty(capture_, prop, val))
+        if (plugin_api_->v0.Capture_setProperty)
+            if (CV_ERROR_OK == plugin_api_->v0.Capture_setProperty(capture_, prop, val))
                 return true;
         return false;
     }
     bool grabFrame() CV_OVERRIDE
     {
-        if (plugin_api_->Capture_grab)
-            if (CV_ERROR_OK == plugin_api_->Capture_grab(capture_))
+        if (plugin_api_->v0.Capture_grab)
+            if (CV_ERROR_OK == plugin_api_->v0.Capture_grab(capture_))
                 return true;
         return false;
     }
@@ -503,8 +503,8 @@ public:
     bool retrieveFrame(int idx, cv::OutputArray img) CV_OVERRIDE
     {
         bool res = false;
-        if (plugin_api_->Capture_retreive)
-            if (CV_ERROR_OK == plugin_api_->Capture_retreive(capture_, idx, retrieve_callback, (cv::_OutputArray*)&img))
+        if (plugin_api_->v0.Capture_retreive)
+            if (CV_ERROR_OK == plugin_api_->v0.Capture_retreive(capture_, idx, retrieve_callback, (cv::_OutputArray*)&img))
                 res = true;
         return res;
     }
@@ -514,7 +514,7 @@ public:
     }
     int getCaptureDomain() CV_OVERRIDE
     {
-        return plugin_api_->captureAPI;
+        return plugin_api_->v0.captureAPI;
     }
 };
 
@@ -534,23 +534,23 @@ public:
     {
         CV_Assert(plugin_api);
         CvPluginWriter writer = NULL;
-        if (plugin_api->api_header.api_version >= 1 && plugin_api->Writer_open_with_params)
+        if (plugin_api->api_header.api_version >= 1 && plugin_api->v1.Writer_open_with_params)
         {
-            CV_Assert(plugin_api->Writer_release);
+            CV_Assert(plugin_api->v0.Writer_release);
             CV_Assert(!filename.empty());
             std::vector<int> vint_params = params.getIntVector();
             int* c_params = &vint_params[0];
             unsigned n_params = (unsigned)(vint_params.size() / 2);
 
-            if (CV_ERROR_OK == plugin_api->Writer_open_with_params(filename.c_str(), fourcc, fps, sz.width, sz.height, c_params, n_params, &writer))
+            if (CV_ERROR_OK == plugin_api->v1.Writer_open_with_params(filename.c_str(), fourcc, fps, sz.width, sz.height, c_params, n_params, &writer))
             {
                 CV_Assert(writer);
                 return makePtr<PluginWriter>(plugin_api, writer);
             }
         }
-        else if (plugin_api->Writer_open)
+        else if (plugin_api->v0.Writer_open)
         {
-            CV_Assert(plugin_api->Writer_release);
+            CV_Assert(plugin_api->v0.Writer_release);
             CV_Assert(!filename.empty());
             const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
             const int depth = params.get(VIDEOWRITER_PROP_DEPTH, CV_8U);
@@ -559,7 +559,7 @@ public:
                 CV_LOG_WARNING(NULL, "Video I/O plugin doesn't support (due to lower API level) creation of VideoWriter with depth != CV_8U");
                 return Ptr<PluginWriter>();
             }
-            if (CV_ERROR_OK == plugin_api->Writer_open(filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, &writer))
+            if (CV_ERROR_OK == plugin_api->v0.Writer_open(filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, &writer))
             {
                 CV_Assert(writer);
                 return makePtr<PluginWriter>(plugin_api, writer);
@@ -576,23 +576,23 @@ public:
 
     ~PluginWriter()
     {
-        CV_DbgAssert(plugin_api_->Writer_release);
-        if (CV_ERROR_OK != plugin_api_->Writer_release(writer_))
+        CV_DbgAssert(plugin_api_->v0.Writer_release);
+        if (CV_ERROR_OK != plugin_api_->v0.Writer_release(writer_))
             CV_LOG_ERROR(NULL, "Video I/O: Can't release writer by plugin '" << plugin_api_->api_header.api_description << "'");
         writer_ = NULL;
     }
     double getProperty(int prop) const CV_OVERRIDE
     {
         double val = -1;
-        if (plugin_api_->Writer_getProperty)
-            if (CV_ERROR_OK != plugin_api_->Writer_getProperty(writer_, prop, &val))
+        if (plugin_api_->v0.Writer_getProperty)
+            if (CV_ERROR_OK != plugin_api_->v0.Writer_getProperty(writer_, prop, &val))
                 val = -1;
         return val;
     }
     bool setProperty(int prop, double val) CV_OVERRIDE
     {
-        if (plugin_api_->Writer_setProperty)
-            if (CV_ERROR_OK == plugin_api_->Writer_setProperty(writer_, prop, val))
+        if (plugin_api_->v0.Writer_setProperty)
+            if (CV_ERROR_OK == plugin_api_->v0.Writer_setProperty(writer_, prop, val))
                 return true;
         return false;
     }
@@ -604,8 +604,8 @@ public:
     {
         cv::Mat img = arr.getMat();
         CV_DbgAssert(writer_);
-        CV_Assert(plugin_api_->Writer_write);
-        if (CV_ERROR_OK != plugin_api_->Writer_write(writer_, img.data, (int)img.step[0], img.cols, img.rows, img.channels()))
+        CV_Assert(plugin_api_->v0.Writer_write);
+        if (CV_ERROR_OK != plugin_api_->v0.Writer_write(writer_, img.data, (int)img.step[0], img.cols, img.rows, img.channels()))
         {
             CV_LOG_DEBUG(NULL, "Video I/O: Can't write frame by plugin '" << plugin_api_->api_header.api_description << "'");
         }
@@ -613,7 +613,7 @@ public:
     }
     int getCaptureDomain() const CV_OVERRIDE
     {
-        return plugin_api_->captureAPI;
+        return plugin_api_->v0.captureAPI;
     }
 };
 
index 052f5eb33120dbefe93aa18011dea646f0e42979..42124c527c97e8d9469e0c2a796decc1c74e1954 100644 (file)
@@ -217,6 +217,8 @@ cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& fi
 
 #if defined(BUILD_PLUGIN)
 
+#define ABI_VERSION 0
+#define API_VERSION 0
 #include "plugin_api.hpp"
 
 namespace cv {
@@ -393,37 +395,36 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char
     }
 }
 
-static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
+static const OpenCV_VideoIO_Plugin_API_preview plugin_api =
 {
     {
-        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
+        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
         CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
         "FFmpeg OpenCV Video I/O plugin"
     },
-    /*  1*/CAP_FFMPEG,
-    /*  2*/cv_capture_open,
-    /*  3*/cv_capture_release,
-    /*  4*/cv_capture_get_prop,
-    /*  5*/cv_capture_set_prop,
-    /*  6*/cv_capture_grab,
-    /*  7*/cv_capture_retrieve,
-    /*  8*/cv_writer_open,
-    /*  9*/cv_writer_release,
-    /* 10*/cv_writer_get_prop,
-    /* 11*/cv_writer_set_prop,
-    /* 12*/cv_writer_write,
-    /* 13 Writer_open_with_params*/NULL
+    {
+        /*  1*/CAP_FFMPEG,
+        /*  2*/cv_capture_open,
+        /*  3*/cv_capture_release,
+        /*  4*/cv_capture_get_prop,
+        /*  5*/cv_capture_set_prop,
+        /*  6*/cv_capture_grab,
+        /*  7*/cv_capture_retrieve,
+        /*  8*/cv_writer_open,
+        /*  9*/cv_writer_release,
+        /* 10*/cv_writer_get_prop,
+        /* 11*/cv_writer_set_prop,
+        /* 12*/cv_writer_write
+    }
 };
 
 } // namespace
 
 const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
 {
-    if (requested_abi_version != 0)
-        return NULL;
-    if (requested_api_version != 0)
-        return NULL;
-    return &cv::plugin_api_v0;
+    if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION)
+        return &cv::plugin_api;
+    return NULL;
 }
 
 #endif // BUILD_PLUGIN
index c68104f58bfb352deb56d421c6437b143365ed64..53d00ec888d8ad6fc5314182f7f1d03042d2ab01 100644 (file)
@@ -1839,6 +1839,8 @@ void handleMessage(GstElement * pipeline)
 
 #if defined(BUILD_PLUGIN)
 
+#define ABI_VERSION 0
+#define API_VERSION 1
 #include "plugin_api.hpp"
 
 namespace cv {
@@ -2054,37 +2056,39 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char
     }
 }
 
-static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
+static const OpenCV_VideoIO_Plugin_API_preview plugin_api =
 {
     {
         sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
         CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
         "GStreamer OpenCV Video I/O plugin"
     },
-    /*  1*/CAP_GSTREAMER,
-    /*  2*/cv_capture_open,
-    /*  3*/cv_capture_release,
-    /*  4*/cv_capture_get_prop,
-    /*  5*/cv_capture_set_prop,
-    /*  6*/cv_capture_grab,
-    /*  7*/cv_capture_retrieve,
-    /*  8*/cv_writer_open,
-    /*  9*/cv_writer_release,
-    /* 10*/cv_writer_get_prop,
-    /* 11*/cv_writer_set_prop,
-    /* 12*/cv_writer_write,
-    /* 13*/cv_writer_open_with_params
+    {
+        /*  1*/CAP_GSTREAMER,
+        /*  2*/cv_capture_open,
+        /*  3*/cv_capture_release,
+        /*  4*/cv_capture_get_prop,
+        /*  5*/cv_capture_set_prop,
+        /*  6*/cv_capture_grab,
+        /*  7*/cv_capture_retrieve,
+        /*  8*/cv_writer_open,
+        /*  9*/cv_writer_release,
+        /* 10*/cv_writer_get_prop,
+        /* 11*/cv_writer_set_prop,
+        /* 12*/cv_writer_write
+    },
+    {
+        /* 13*/cv_writer_open_with_params
+    }
 };
 
 } // namespace
 
 const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
 {
-    if (requested_abi_version != 0)
-        return NULL;
-    if (requested_api_version != 0 && requested_api_version != 1)
-        return NULL;
-    return &cv::plugin_api_v0;
+    if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION)
+        return &cv::plugin_api;
+    return NULL;
 }
 
 #endif // BUILD_PLUGIN
index 49210e6a306fd10e9c320cdcf27a5b6b1061a5ef..846245faf0707598cfbd7e76a592ae086e43f4d1 100644 (file)
@@ -185,37 +185,36 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char
     }
 }
 
-static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
+static const OpenCV_VideoIO_Plugin_API_preview plugin_api =
 {
     {
-        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
+        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
         CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
         "MediaSDK OpenCV Video I/O plugin"
     },
-    /*  1*/CAP_INTEL_MFX,
-    /*  2*/cv_capture_open,
-    /*  3*/cv_capture_release,
-    /*  4*/cv_capture_get_prop,
-    /*  5*/cv_capture_set_prop,
-    /*  6*/cv_capture_grab,
-    /*  7*/cv_capture_retrieve,
-    /*  8*/cv_writer_open,
-    /*  9*/cv_writer_release,
-    /* 10*/cv_writer_get_prop,
-    /* 11*/cv_writer_set_prop,
-    /* 12*/cv_writer_write,
-    /* 13 Writer_open_with_params*/NULL
+    {
+        /*  1*/CAP_INTEL_MFX,
+        /*  2*/cv_capture_open,
+        /*  3*/cv_capture_release,
+        /*  4*/cv_capture_get_prop,
+        /*  5*/cv_capture_set_prop,
+        /*  6*/cv_capture_grab,
+        /*  7*/cv_capture_retrieve,
+        /*  8*/cv_writer_open,
+        /*  9*/cv_writer_release,
+        /* 10*/cv_writer_get_prop,
+        /* 11*/cv_writer_set_prop,
+        /* 12*/cv_writer_write
+    }
 };
 
 } // namespace
 
 const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
 {
-    if (requested_abi_version != 0)
-        return NULL;
-    if (requested_api_version != 0)
-        return NULL;
-    return &cv::plugin_api_v0;
+    if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION)
+        return &cv::plugin_api;
+    return NULL;
 }
 
 #endif // BUILD_PLUGIN
index 137dd2103dbde2b49206e2c22ff06b3bc72b4af7..a1d4a2813105a6af4b1a3b59ab8e8508a3c82911 100644 (file)
@@ -1680,6 +1680,8 @@ cv::Ptr<cv::IVideoWriter> cv::cvCreateVideoWriter_MSMF( const std::string& filen
 
 #if defined(BUILD_PLUGIN)
 
+#define ABI_VERSION 0
+#define API_VERSION 0
 #include "plugin_api.hpp"
 
 namespace cv {
@@ -1863,36 +1865,36 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char*
     }
 }
 
-static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
+static const OpenCV_VideoIO_Plugin_API_preview plugin_api =
 {
     {
-        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
+        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
         CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
         "Microsoft Media Foundation OpenCV Video I/O plugin"
     },
-    /*  1*/CAP_MSMF,
-    /*  2*/cv_capture_open,
-    /*  3*/cv_capture_release,
-    /*  4*/cv_capture_get_prop,
-    /*  5*/cv_capture_set_prop,
-    /*  6*/cv_capture_grab,
-    /*  7*/cv_capture_retrieve,
-    /*  8*/cv_writer_open,
-    /*  9*/cv_writer_release,
-    /* 10*/cv_writer_get_prop,
-    /* 11*/cv_writer_set_prop,
-    /* 12*/cv_writer_write
+    {
+        /*  1*/CAP_MSMF,
+        /*  2*/cv_capture_open,
+        /*  3*/cv_capture_release,
+        /*  4*/cv_capture_get_prop,
+        /*  5*/cv_capture_set_prop,
+        /*  6*/cv_capture_grab,
+        /*  7*/cv_capture_retrieve,
+        /*  8*/cv_writer_open,
+        /*  9*/cv_writer_release,
+        /* 10*/cv_writer_get_prop,
+        /* 11*/cv_writer_set_prop,
+        /* 12*/cv_writer_write
+    }
 };
 
 } // namespace
 
 const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
 {
-    if (requested_abi_version != 0)
-        return NULL;
-    if (requested_api_version != 0)
-        return NULL;
-    return &cv::plugin_api_v0;
+    if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION)
+        return &cv::plugin_api;
+    return NULL;
 }
 
 #endif // BUILD_PLUGIN
index 9f9b033247a52d7ac1f584cf32d065185b80c52d..eadba1554689ed96b530317575803da111190df7 100644 (file)
@@ -356,6 +356,8 @@ void VideoCapture_uEye::unlock_image_buffer()
 // plugin glue
 #if defined(BUILD_PLUGIN)
 
+#define ABI_VERSION 0
+#define API_VERSION 0
 #include "plugin_api.hpp"
 
 namespace cv
@@ -464,37 +466,36 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter /*handle*/, const unsigned c
     return CV_ERROR_FAIL;
 }
 
-const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
+const OpenCV_VideoIO_Plugin_API_preview plugin_api =
 {
     {
-        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
+        sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
         CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
         "uEye OpenCV Video I/O plugin"
     },
-    /*  1*/CAP_UEYE,
-    /*  2*/cv_capture_open,
-    /*  3*/cv_capture_release,
-    /*  4*/cv_capture_get_prop,
-    /*  5*/cv_capture_set_prop,
-    /*  6*/cv_capture_grab,
-    /*  7*/cv_capture_retrieve,
-    /*  8*/cv_writer_open,
-    /*  9*/cv_writer_release,
-    /* 10*/cv_writer_get_prop,
-    /* 11*/cv_writer_set_prop,
-    /* 12*/cv_writer_write,
-    /* 13 Writer_open_with_params*/NULL
+    {
+        /*  1*/CAP_UEYE,
+        /*  2*/cv_capture_open,
+        /*  3*/cv_capture_release,
+        /*  4*/cv_capture_get_prop,
+        /*  5*/cv_capture_set_prop,
+        /*  6*/cv_capture_grab,
+        /*  7*/cv_capture_retrieve,
+        /*  8*/cv_writer_open,
+        /*  9*/cv_writer_release,
+        /* 10*/cv_writer_get_prop,
+        /* 11*/cv_writer_set_prop,
+        /* 12*/cv_writer_write
+    }
 };
 } // namespace
 } // namespace cv
 
 const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int requested_abi_version, int requested_api_version, void* /*reserved=NULL*/) CV_NOEXCEPT
 {
-    if (requested_abi_version != 0)
-        return NULL;
-    if (requested_api_version != 0)
-        return NULL;
-    return &cv::plugin_api_v0;
+    if (requested_abi_version == ABI_VERSION && requested_api_version <= API_VERSION)
+        return &cv::plugin_api;
+    return NULL;
 }
 
 #endif // BUILD_PLUGIN
index fa63d3fa7197f0d6f2cd3e46c61d43339f0365b9..1281ab57ee2ab19025fbdfbec62191d4438b81a5 100644 (file)
@@ -8,15 +8,28 @@
 #include <opencv2/core/cvdef.h>
 #include <opencv2/core/llapi/llapi.h>
 
-// increase for backward-compatible changes, e.g. add new function
-// Main API <= Plugin API -> plugin is fully compatible
-// Main API > Plugin API -> plugin is not compatible, caller should use shim code to use plugins with old API
+#if !defined(BUILD_PLUGIN)
+
+/// increased for backward-compatible changes, e.g. add new function
+/// Caller API <= Plugin API -> plugin is fully compatible
+/// Caller API > Plugin API -> plugin is not fully compatible, caller should use extra checks to use plugins with older API
 #define API_VERSION 1 // preview
-// increase for incompatible changes, e.g. remove function argument
-// Main ABI == Plugin ABI -> plugin is compatible
-// Main ABI > Plugin ABI -> plugin is not compatible, caller should use shim code to use old ABI plugins
+
+/// increased for incompatible changes, e.g. remove function argument
+/// Caller ABI == Plugin ABI -> plugin is compatible
+/// Caller ABI > Plugin ABI -> plugin is not compatible, caller should use shim code to use old ABI plugins (caller may know how lower ABI works, so it is possible)
+/// Caller ABI < Plugin ABI -> plugin can't be used (plugin should provide interface with lower ABI to handle that)
 #define ABI_VERSION 0 // preview
 
+#else // !defined(BUILD_PLUGIN)
+
+#if !defined(ABI_VERSION) || !defined(API_VERSION)
+#error "Plugin must define ABI_VERSION and API_VERSION before including plugin_api.hpp"
+#endif
+
+#endif // !defined(BUILD_PLUGIN)
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -26,10 +39,8 @@ typedef CvResult (CV_API_CALL *cv_videoio_retrieve_cb_t)(int stream_idx, unsigne
 typedef struct CvPluginCapture_t* CvPluginCapture;
 typedef struct CvPluginWriter_t* CvPluginWriter;
 
-typedef struct OpenCV_VideoIO_Plugin_API_preview
+struct OpenCV_VideoIO_Plugin_API_v0_0_api_entries
 {
-    OpenCV_API_Header api_header;
-
     /** OpenCV capture ID (VideoCaptureAPIs)
     @note API-ENTRY 1, API-Version == 0
      */
@@ -148,8 +159,10 @@ typedef struct OpenCV_VideoIO_Plugin_API_preview
     @note API-CALL 12, API-Version == 0
      */
     CvResult (CV_API_CALL *Writer_write)(CvPluginWriter handle, const unsigned char *data, int step, int width, int height, int cn);
+}; // OpenCV_VideoIO_Plugin_API_v0_0_api_entries
 
-
+struct OpenCV_VideoIO_Plugin_API_v0_1_api_entries
+{
     /** @brief Try to open video writer
 
     @param filename Destination location
@@ -168,8 +181,29 @@ typedef struct OpenCV_VideoIO_Plugin_API_preview
         int* params, unsigned n_params,
         CV_OUT CvPluginWriter* handle
     );
+}; // OpenCV_VideoIO_Plugin_API_v0_1_api_entries
 
-} OpenCV_VideoIO_Plugin_API_preview;
+typedef struct OpenCV_VideoIO_Plugin_API_preview_v0
+{
+    OpenCV_API_Header api_header;
+    struct OpenCV_VideoIO_Plugin_API_v0_0_api_entries v0;
+} OpenCV_VideoIO_Plugin_API_preview_v0;
+
+typedef struct OpenCV_VideoIO_Plugin_API_preview_v1
+{
+    OpenCV_API_Header api_header;
+    struct OpenCV_VideoIO_Plugin_API_v0_0_api_entries v0;
+    struct OpenCV_VideoIO_Plugin_API_v0_1_api_entries v1;
+} OpenCV_VideoIO_Plugin_API_preview_v1;
+
+
+#if ABI_VERSION == 0 && API_VERSION == 1
+typedef struct OpenCV_VideoIO_Plugin_API_preview_v1 OpenCV_VideoIO_Plugin_API_preview;
+#elif ABI_VERSION == 0 && API_VERSION == 0
+typedef struct OpenCV_VideoIO_Plugin_API_preview_v0 OpenCV_VideoIO_Plugin_API_preview;
+#else
+#error "Not supported configuration: check ABI_VERSION/API_VERSION"
+#endif
 
 #ifdef BUILD_PLUGIN