mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 08:13:04 +04:00
Merge pull request #28967 from IbrahimNamdari:add-video-context-manager
Python: add context manager compatibility for VideoCapture and VideoWriter #28967 ### Description This PR implements the context manager protocol (`with` statement support) for `cv2.VideoCapture` and `cv2.VideoWriter` objects in Python. ### Problem Currently, these classes do not support the context manager protocol, leading to a `TypeError: ... object does not support the context manager protocol` when used with a `with` block. As reported in issue #28956, if an exception occurs before an explicit `.release()` call, the video resource or file remains locked in the system[cite: 298, 309]. ### Identification & Motivation By analyzing the issue and the Python binding structure of OpenCV, I identified that while the core logic resides in C++, the Pythonic behavior can be enhanced by injecting `__enter__` and `__exit__` methods during the module initialization. This ensures that resources are automatically and safely released even if the program execution is interrupted by an error[cite: 298, 325]. ### Solution I have modified `modules/python/package/cv2/__init__.py` to dynamically inject the necessary methods: 1. Defined `_video_enter` to return the object itself (standard context manager behavior). 2. Defined `_video_exit` to trigger the `.release()` method automatically. 3. Injected these methods into `VideoCapture` and `VideoWriter` classes immediately after the `bootstrap()` function to ensure the native C++ classes are correctly loaded into the global namespace. Fixes #28956
This commit is contained in:
@@ -141,4 +141,34 @@ bool pyopencv_to(PyObject* obj, Ptr<cv::IStreamReader>& p, const ArgInfo&)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user