chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:06:04 +08:00
commit 86c9b1c39f
7743 changed files with 3316339 additions and 0 deletions
@@ -0,0 +1,174 @@
#ifdef HAVE_OPENCV_VIDEOIO
typedef std::vector<VideoCaptureAPIs> vector_VideoCaptureAPIs;
typedef std::vector<VideoCapture> vector_VideoCapture;
template<> struct pyopencvVecConverter<cv::VideoCaptureAPIs>
{
static bool to(PyObject* obj, std::vector<cv::VideoCaptureAPIs>& value, const ArgInfo& info)
{
return pyopencv_to_generic_vec(obj, value, info);
}
static PyObject* from(const std::vector<cv::VideoCaptureAPIs>& value)
{
return pyopencv_from_generic_vec(value);
}
};
template<>
bool pyopencv_to(PyObject *o, std::vector<cv::VideoCaptureAPIs>& apis, const ArgInfo& info)
{
return pyopencvVecConverter<cv::VideoCaptureAPIs>::to(o, apis, info);
}
template<> bool pyopencv_to(PyObject* obj, cv::VideoCapture& stream, const ArgInfo& info)
{
Ptr<VideoCapture> * obj_getp = nullptr;
if (!pyopencv_VideoCapture_getp(obj, obj_getp))
return (failmsgp("Incorrect type of self (must be 'VideoCapture' or its derivative)") != nullptr);
stream = **obj_getp;
return true;
}
class PythonStreamReader : public cv::IStreamReader
{
public:
PythonStreamReader(PyObject* _obj = nullptr) : obj(_obj)
{
if (obj)
Py_INCREF(obj);
}
~PythonStreamReader()
{
if (obj)
Py_DECREF(obj);
}
long long read(char* buffer, long long size) CV_OVERRIDE
{
if (!obj)
return 0;
PyObject* ioBase = reinterpret_cast<PyObject*>(obj);
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
PyObject* py_size = pyopencv_from(static_cast<int>(size));
PyObject* res = PyObject_CallMethodObjArgs(ioBase, PyString_FromString("read"), py_size, NULL);
bool hasPyReadError = PyErr_Occurred() != nullptr;
char* src = PyBytes_AsString(res);
size_t len = static_cast<size_t>(PyBytes_Size(res));
bool hasPyBytesError = PyErr_Occurred() != nullptr;
if (src && len <= static_cast<size_t>(size))
{
std::memcpy(buffer, src, len);
}
Py_DECREF(res);
Py_DECREF(py_size);
PyGILState_Release(gstate);
if (hasPyReadError)
CV_Error(cv::Error::StsError, "Python .read() call error");
if (hasPyBytesError)
CV_Error(cv::Error::StsError, "Python buffer access error");
CV_CheckLE(len, static_cast<size_t>(size), "Stream chunk size should be less or equal than requested size");
return len;
}
long long seek(long long offset, int way) CV_OVERRIDE
{
if (!obj)
return 0;
PyObject* ioBase = reinterpret_cast<PyObject*>(obj);
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
PyObject* py_offset = pyopencv_from(static_cast<int>(offset));
PyObject* py_whence = pyopencv_from(way);
PyObject* res = PyObject_CallMethodObjArgs(ioBase, PyString_FromString("seek"), py_offset, py_whence, NULL);
bool hasPySeekError = PyErr_Occurred() != nullptr;
long long pos = PyLong_AsLongLong(res);
bool hasPyConvertError = PyErr_Occurred() != nullptr;
Py_DECREF(res);
Py_DECREF(py_offset);
Py_DECREF(py_whence);
PyGILState_Release(gstate);
if (hasPySeekError)
CV_Error(cv::Error::StsError, "Python .seek() call error");
if (hasPyConvertError)
CV_Error(cv::Error::StsError, "Python .seek() result => long long conversion error");
return pos;
}
private:
PyObject* obj;
};
template<>
bool pyopencv_to(PyObject* obj, Ptr<cv::IStreamReader>& p, const ArgInfo&)
{
if (!obj)
return false;
PyObject* ioModule = PyImport_ImportModule("io");
PyObject* type = PyObject_GetAttrString(ioModule, "BufferedIOBase");
Py_DECREF(ioModule);
bool isValidPyType = PyObject_IsInstance(obj, type) == 1;
Py_DECREF(type);
if (!isValidPyType)
{
PyErr_SetString(PyExc_TypeError, "Input stream should be derived from io.BufferedIOBase");
return false;
}
if (!PyErr_Occurred()) {
p = makePtr<PythonStreamReader>(obj);
return true;
}
return false;
}
static PyObject* pycvVideoEnter(PyObject* self, PyObject* /*args*/, PyObject* /*kw*/) {
Py_INCREF(self);
return self;
}
static PyObject* pycvVideoCaptureExit(PyObject* self, PyObject* /*args*/, PyObject* /*kw*/) {
Ptr<cv::VideoCapture>* obj_getp = nullptr;
if (pyopencv_VideoCapture_getp(self, obj_getp) && obj_getp && *obj_getp) {
(*obj_getp)->release();
}
Py_RETURN_NONE;
}
static PyObject* pycvVideoWriterExit(PyObject* self, PyObject* /*args*/, PyObject* /*kw*/) {
Ptr<cv::VideoWriter>* obj_getp = nullptr;
if (pyopencv_VideoWriter_getp(self, obj_getp) && obj_getp && *obj_getp) {
(*obj_getp)->release();
}
Py_RETURN_NONE;
}
#define PYOPENCV_EXTRA_METHODS_VideoCapture \
{"__enter__", CV_PY_FN_WITH_KW(pycvVideoEnter), "Context manager enter"}, \
{"__exit__", CV_PY_FN_WITH_KW(pycvVideoCaptureExit), "Context manager exit"},
#define PYOPENCV_EXTRA_METHODS_VideoWriter \
{"__enter__", CV_PY_FN_WITH_KW(pycvVideoEnter), "Context manager enter"}, \
{"__exit__", CV_PY_FN_WITH_KW(pycvVideoWriterExit), "Context manager exit"},
#endif // HAVE_OPENCV_VIDEOIO
@@ -0,0 +1,109 @@
#!/usr/bin/env python
from __future__ import print_function
import numpy as np
import cv2 as cv
import io
import sys
import tempfile
from tests_common import NewOpenCVTests
class Bindings(NewOpenCVTests):
def check_name(self, name):
#print(name)
self.assertFalse(name == None)
self.assertFalse(name == "")
def test_registry(self):
self.check_name(cv.videoio_registry.getBackendName(cv.CAP_ANY));
self.check_name(cv.videoio_registry.getBackendName(cv.CAP_FFMPEG))
self.check_name(cv.videoio_registry.getBackendName(cv.CAP_OPENCV_MJPEG))
backends = cv.videoio_registry.getBackends()
for backend in backends:
self.check_name(cv.videoio_registry.getBackendName(backend))
def test_capture_stream_file(self):
if sys.version_info[0] < 3:
raise self.skipTest('Python 3.x required')
api_pref = None
for backend in cv.videoio_registry.getStreamBufferedBackends():
if not cv.videoio_registry.hasBackend(backend):
continue
if not cv.videoio_registry.isBackendBuiltIn(backend):
_, abi, api = cv.videoio_registry.getStreamBufferedBackendPluginVersion(backend)
if (abi < 1 or (abi == 1 and api < 2)):
continue
api_pref = backend
break
if not api_pref:
raise self.skipTest("No available backends")
with open(self.find_file("cv/video/768x576.avi"), "rb") as f:
cap = cv.VideoCapture(f, api_pref, [])
self.assertTrue(cap.isOpened())
hasFrame, frame = cap.read()
self.assertTrue(hasFrame)
self.assertEqual(frame.shape, (576, 768, 3))
def test_capture_stream_buffer(self):
if sys.version_info[0] < 3:
raise self.skipTest('Python 3.x required')
api_pref = None
for backend in cv.videoio_registry.getStreamBufferedBackends():
if not cv.videoio_registry.hasBackend(backend):
continue
if not cv.videoio_registry.isBackendBuiltIn(backend):
_, abi, api = cv.videoio_registry.getStreamBufferedBackendPluginVersion(backend)
if (abi < 1 or (abi == 1 and api < 2)):
continue
api_pref = backend
break
if not api_pref:
raise self.skipTest("No available backends")
class BufferStream(io.BufferedIOBase):
def __init__(self, filepath):
self.f = open(filepath, "rb")
def read(self, size=-1):
return self.f.read(size)
def seek(self, offset, whence):
return self.f.seek(offset, whence)
def __del__(self):
self.f.close()
stream = BufferStream(self.find_file("cv/video/768x576.avi"))
cap = cv.VideoCapture(stream, api_pref, [])
self.assertTrue(cap.isOpened())
hasFrame, frame = cap.read()
self.assertTrue(hasFrame)
self.assertEqual(frame.shape, (576, 768, 3))
def test_context_manager(self):
video_file = self.find_file("cv/video/768x576.avi")
with cv.VideoCapture(video_file) as cap:
self.assertTrue(cap.isOpened(), "VideoCapture should be opened within context manager")
with tempfile.NamedTemporaryFile(suffix='.avi') as tmp:
with cv.VideoWriter(tmp.name, cv.VideoWriter_fourcc(*'MJPG'), 25, (640, 480)) as writer:
self.assertTrue(isinstance(writer, cv.VideoWriter))
try:
with cv.VideoCapture(video_file) as cap:
self.assertTrue(cap.isOpened())
raise RuntimeError("Testing context manager exception safety")
except RuntimeError:
pass
if __name__ == '__main__':
NewOpenCVTests.bootstrap()