├── Makefile ├── _Makefile ├── class_rtsp.cpp ├── pyboostcvconverter ├── pyboostcvconverter.cpp └── pyboostcvconverter.hpp ├── readme.md └── rtsp.py /Makefile: -------------------------------------------------------------------------------- 1 | OBJS = rtsp.o pyboostcvconverter.o 2 | target = pbcvt.so 3 | CC = aarch64-linux-gnu-g++ 4 | 5 | temp_dir := build/temp.linux-aarch64-3.7 6 | $(shell if [ ! -e $(temp_dir) ];then mkdir -p $(temp_dir); fi) 7 | 8 | $(target): $(OBJS) 9 | $(CC) -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,relro -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-aarch64-3.7/*.o -lboost_python3 -o pbcvt.so -lrockchip_rtsp -lrockchip_mpp -lcurl -lrockchip_rga -lpthread -lopencv_core -lopencv_highgui -lopencv_imgcodecs 10 | 11 | rtsp.o: class_rtsp.cpp 12 | $(CC) -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.7m -c class_rtsp.cpp -o build/temp.linux-aarch64-3.7/rtsp.o 13 | 14 | pyboostcvconverter.o: pyboostcvconverter/pyboostcvconverter.cpp 15 | $(CC) -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.7m -c pyboostcvconverter/pyboostcvconverter.cpp -o build/temp.linux-aarch64-3.7/pyboostcvconverter.o 16 | 17 | .PHONY: clean 18 | clean: 19 | rm -rf build/temp.linux-aarch64-3.7/*.o $(target) 20 | -------------------------------------------------------------------------------- /_Makefile: -------------------------------------------------------------------------------- 1 | OBJS = rtsp.o pyboostcvconverter.o 2 | target = pbcvt.so 3 | CC = aarch64-linux-gnu-g++ 4 | 5 | temp_dir := build/temp.linux-aarch64-3.7 6 | $(shell if [ ! -e $(temp_dir) ];then mkdir -p $(temp_dir); fi) 7 | 8 | $(target): $(OBJS) 9 | $(CC) -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,relro -g -fstack-protector-strong -Wformat -Werror=format-security \ 10 | -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-aarch64-3.7/*.o -lboost_python3 -o pbcvt.so \ 11 | -lrockchip_rtsp -lrockchip_mpp -lcurl -lrockchip_rga -lpthread \ 12 | -lopencv_core -lopencv_highgui -lopencv_imgcodecs -I/usr/local/include/opencv4 -lboost_numpy37 13 | 14 | rtsp.o: class_rtsp.cpp 15 | $(CC) -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 \ 16 | -fPIC -I/usr/include/python3.7m -c class_rtsp.cpp -o build/temp.linux-aarch64-3.7/rtsp.o -I/usr/local/include/opencv4 17 | 18 | pyboostcvconverter.o: pyboostcvconverter/pyboostcvconverter.cpp 19 | $(CC) -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 \ 20 | -fPIC -I/usr/include/python3.7m -c pyboostcvconverter/pyboostcvconverter.cpp -o build/temp.linux-aarch64-3.7/pyboostcvconverter.o -I/usr/local/include/opencv4 21 | 22 | .PHONY: clean 23 | clean: 24 | rm -rf build/temp.linux-aarch64-3.7/*.o $(target) 25 | -------------------------------------------------------------------------------- /class_rtsp.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by lucy on 2020/10/29.封装版本 3 | // 说明:完成于2020/11/02,类 4 | // bug修复已完成 5 | // 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define RTSP_DEBUG 0 20 | 21 | #define PY_ARRAY_UNIQUE_SYMBOL pbcvt_ARRAY_API 22 | #include 23 | #include "pyboostcvconverter/pyboostcvconverter.hpp" 24 | #if (PY_VERSION_HEX >= 0x03000000) 25 | static void *init_ar() { 26 | #else 27 | static void init_ar(){ 28 | #endif 29 | Py_Initialize(); 30 | 31 | import_array(); 32 | return NUMPY_IMPORT_ARRAY_RETVAL; 33 | } 34 | 35 | using namespace std; 36 | 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | extern "C" { 43 | #include 44 | } 45 | 46 | static MppDecoder *mpp_dec = NULL; 47 | static RockchipRga *rga; 48 | int resize_w = 1000,resize_h = 1000; 49 | static int frame_size = resize_w * resize_h * 3; 50 | unsigned char *frame_rgb = NULL; 51 | clock_t time_start=0; 52 | clock_t time_end; 53 | 54 | // 打印当前时间 55 | // time_t t=time(0); 56 | // tm *dt=localtime(&t); 57 | // cout<tm_hour<<":"<tm_min<<":"<tm_sec<ops->enqueue(mpp_dec, buf, len); 71 | } 72 | 73 | 74 | namespace pbcvt { 75 | using namespace boost::python; 76 | struct Rtsp 77 | { 78 | public: 79 | RtspClient rtsp_client; 80 | 81 | Rtsp(string url,string user,string pwd):rtsp_client(url, user, pwd){ 82 | frame_rgb = (unsigned char *)malloc(frame_size); 83 | 84 | cout << "[ RTSP_URL ] " << url << endl; 85 | cout << "[ RTSP_USER ] " << user << endl; 86 | cout << "[ RTSP_PWD ] " << pwd << endl; 87 | } 88 | 89 | PyObject *ret_to_python(void); 90 | bool rtsp_main(void); 91 | int close(void); 92 | 93 | }; 94 | 95 | BOOST_PYTHON_MODULE(pbcvt) 96 | { 97 | init_ar(); 98 | to_python_converter(); 99 | matFromNDArrayBoostConverter(); 100 | class_("Rtsp",init()) 101 | .def("rtsp_main", &Rtsp::rtsp_main) 102 | .def("ret_to_python", &Rtsp::ret_to_python) 103 | .def("close", &Rtsp::close); 104 | } 105 | 106 | PyObject * Rtsp::ret_to_python(void) 107 | { 108 | #if RTSP_DEBUG 109 | time_start=clock(); 110 | #endif 111 | int ret; 112 | DecFrame *frame = mpp_dec->ops->dequeue_timeout(mpp_dec, 300); 113 | if (frame == NULL) { 114 | return NULL; 115 | } 116 | cv::Mat img(resize_h , resize_w , CV_8UC3, frame_rgb); 117 | if (!frame_rgb) { 118 | return NULL; 119 | } 120 | rga->ops->setSrcBufferPtr(rga, frame->data); 121 | ret = rga->ops->go(rga); 122 | if (!ret) { 123 | mpp_dec->ops->freeFrame(frame); 124 | PyObject *res = pbcvt::fromMatToNDArray(img); 125 | #if RTSP_DEBUG 126 | time_end=clock(); 127 | cout<<"[ c++ ] "<<(double)(time_end-time_start)/CLOCKS_PER_SEC<<"s"<ops->dequeue_timeout(mpp_dec, 300); 155 | if (frame != NULL){ 156 | run = 0; 157 | int width = frame->width; 158 | int height = frame->height; 159 | 160 | rga->ops->initCtx(rga); 161 | rga->ops->setRotate(rga, RGA_ROTATE_NONE); 162 | rga->ops->setSrcFormat(rga, V4L2_PIX_FMT_NV12, width, height); 163 | rga->ops->setDstFormat(rga, V4L2_PIX_FMT_RGB24, resize_w, resize_h); 164 | 165 | mpp_dec->ops->freeFrame(frame); 166 | 167 | rga->ops->setDstBufferPtr(rga, frame_rgb); 168 | #if RTSP_DEBUG 169 | cout<<" true "<< endl; 170 | #endif 171 | return true; 172 | } 173 | else { 174 | std::cout << "frame NULL!\n" << std::endl; 175 | } 176 | } 177 | } 178 | 179 | int Rtsp::close(void) 180 | { 181 | rtsp_client.disable(); 182 | RgaDestroy(rga); 183 | 184 | MppDecoderDestroy(mpp_dec); 185 | 186 | free(frame_rgb); 187 | return 0; 188 | } 189 | } 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /pyboostcvconverter/pyboostcvconverter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CV4BoostConverter.cpp 3 | * 4 | */ 5 | #define NO_IMPORT_ARRAY 6 | #define PY_ARRAY_UNIQUE_SYMBOL pbcvt_ARRAY_API 7 | #include "pyboostcvconverter.hpp" 8 | #if !defined CV_VERSION_EPOCH && CV_VERSION_MAJOR == 4 9 | namespace pbcvt { 10 | using namespace cv; 11 | //=================== ERROR HANDLING ========================================================= 12 | 13 | static int failmsg(const char *fmt, ...) { 14 | char str[1000]; 15 | 16 | va_list ap; 17 | va_start(ap, fmt); 18 | vsnprintf(str, sizeof(str), fmt, ap); 19 | va_end(ap); 20 | 21 | PyErr_SetString(PyExc_TypeError, str); 22 | return 0; 23 | } 24 | 25 | //=================== THREADING ============================================================== 26 | class PyAllowThreads { 27 | public: 28 | PyAllowThreads() : 29 | _state(PyEval_SaveThread()) { 30 | } 31 | ~PyAllowThreads() { 32 | PyEval_RestoreThread(_state); 33 | } 34 | private: 35 | PyThreadState* _state; 36 | }; 37 | 38 | class PyEnsureGIL { 39 | public: 40 | PyEnsureGIL() : 41 | _state(PyGILState_Ensure()) { 42 | } 43 | ~PyEnsureGIL() { 44 | PyGILState_Release(_state); 45 | } 46 | private: 47 | PyGILState_STATE _state; 48 | }; 49 | 50 | enum { 51 | ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 52 | }; 53 | 54 | class NumpyAllocator: 55 | public MatAllocator { 56 | public: 57 | NumpyAllocator() { 58 | stdAllocator = Mat::getStdAllocator(); 59 | } 60 | ~NumpyAllocator() { 61 | } 62 | 63 | UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, 64 | size_t* step) const { 65 | UMatData* u = new UMatData(this); 66 | u->data = u->origdata = (uchar*) PyArray_DATA((PyArrayObject*) o); 67 | npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); 68 | for (int i = 0; i < dims - 1; i++) 69 | step[i] = (size_t) _strides[i]; 70 | step[dims - 1] = CV_ELEM_SIZE(type); 71 | u->size = sizes[0] * step[0]; 72 | u->userdata = o; 73 | return u; 74 | } 75 | 76 | UMatData* allocate(int dims0, const int* sizes, int type, void* data, 77 | size_t* step, cv::AccessFlag flags, UMatUsageFlags usageFlags) const { 78 | if (data != 0) { 79 | CV_Error(Error::StsAssert, "The data should normally be NULL!"); 80 | // probably this is safe to do in such extreme case 81 | return stdAllocator->allocate(dims0, sizes, type, data, step, flags, 82 | usageFlags); 83 | } 84 | PyEnsureGIL gil; 85 | 86 | int depth = CV_MAT_DEPTH(type); 87 | int cn = CV_MAT_CN(type); 88 | const int f = (int) (sizeof(size_t) / 8); 89 | int typenum = 90 | depth == CV_8U ? NPY_UBYTE : 91 | depth == CV_8S ? NPY_BYTE : 92 | depth == CV_16U ? NPY_USHORT : 93 | depth == CV_16S ? NPY_SHORT : 94 | depth == CV_32S ? NPY_INT : 95 | depth == CV_32F ? NPY_FLOAT : 96 | depth == CV_64F ? 97 | NPY_DOUBLE : 98 | f * NPY_ULONGLONG + (f ^ 1) * NPY_UINT; 99 | int i, dims = dims0; 100 | cv::AutoBuffer _sizes(dims + 1); 101 | for (i = 0; i < dims; i++) 102 | _sizes[i] = sizes[i]; 103 | if (cn > 1) 104 | _sizes[dims++] = cn; 105 | PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum); 106 | if (!o) 107 | CV_Error_(Error::StsError, 108 | ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims)); 109 | return allocate(o, dims0, sizes, type, step); 110 | } 111 | 112 | bool allocate(UMatData* u, cv::AccessFlag accessFlags, 113 | UMatUsageFlags usageFlags) const { 114 | return stdAllocator->allocate(u, accessFlags, usageFlags); 115 | } 116 | 117 | void deallocate(UMatData* u) const { 118 | if (u) { 119 | PyEnsureGIL gil; 120 | PyObject* o = (PyObject*) u->userdata; 121 | Py_XDECREF(o); 122 | delete u; 123 | } 124 | } 125 | 126 | const MatAllocator* stdAllocator; 127 | }; 128 | 129 | //=================== ALLOCATOR INITIALIZTION ================================================== 130 | NumpyAllocator g_numpyAllocator; 131 | 132 | //=================== STANDALONE CONVERTER FUNCTIONS ========================================= 133 | 134 | PyObject* fromMatToNDArray(const Mat& m) { 135 | if (!m.data) 136 | Py_RETURN_NONE; 137 | Mat temp, 138 | *p = (Mat*) &m; 139 | if (!p->u || p->allocator != &g_numpyAllocator) { 140 | temp.allocator = &g_numpyAllocator; 141 | ERRWRAP2(m.copyTo(temp)); 142 | p = &temp; 143 | } 144 | PyObject* o = (PyObject*) p->u->userdata; 145 | Py_INCREF(o); 146 | return o; 147 | } 148 | 149 | Mat fromNDArrayToMat(PyObject* o) { 150 | cv::Mat m; 151 | bool allowND = true; 152 | if (!PyArray_Check(o)) { 153 | failmsg("argument is not a numpy array"); 154 | if (!m.data) 155 | m.allocator = &g_numpyAllocator; 156 | } else { 157 | PyArrayObject* oarr = (PyArrayObject*) o; 158 | 159 | bool needcopy = false, needcast = false; 160 | int typenum = PyArray_TYPE(oarr), new_typenum = typenum; 161 | int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S : 162 | typenum == NPY_USHORT ? CV_16U : 163 | typenum == NPY_SHORT ? CV_16S : 164 | typenum == NPY_INT ? CV_32S : 165 | typenum == NPY_INT32 ? CV_32S : 166 | typenum == NPY_FLOAT ? CV_32F : 167 | typenum == NPY_DOUBLE ? CV_64F : -1; 168 | 169 | if (type < 0) { 170 | if (typenum == NPY_INT64 || typenum == NPY_UINT64 171 | || type == NPY_LONG) { 172 | needcopy = needcast = true; 173 | new_typenum = NPY_INT; 174 | type = CV_32S; 175 | } else { 176 | failmsg("Argument data type is not supported"); 177 | m.allocator = &g_numpyAllocator; 178 | return m; 179 | } 180 | } 181 | 182 | #ifndef CV_MAX_DIM 183 | const int CV_MAX_DIM = 32; 184 | #endif 185 | 186 | int ndims = PyArray_NDIM(oarr); 187 | if (ndims >= CV_MAX_DIM) { 188 | failmsg("Dimensionality of argument is too high"); 189 | if (!m.data) 190 | m.allocator = &g_numpyAllocator; 191 | return m; 192 | } 193 | 194 | int size[CV_MAX_DIM + 1]; 195 | size_t step[CV_MAX_DIM + 1]; 196 | size_t elemsize = CV_ELEM_SIZE1(type); 197 | const npy_intp* _sizes = PyArray_DIMS(oarr); 198 | const npy_intp* _strides = PyArray_STRIDES(oarr); 199 | bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX; 200 | 201 | for (int i = ndims - 1; i >= 0 && !needcopy; i--) { 202 | // these checks handle cases of 203 | // a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases 204 | // b) transposed arrays, where _strides[] elements go in non-descending order 205 | // c) flipped arrays, where some of _strides[] elements are negative 206 | if ((i == ndims - 1 && (size_t) _strides[i] != elemsize) 207 | || (i < ndims - 1 && _strides[i] < _strides[i + 1])) 208 | needcopy = true; 209 | } 210 | 211 | if (ismultichannel && _strides[1] != (npy_intp) elemsize * _sizes[2]) 212 | needcopy = true; 213 | 214 | if (needcopy) { 215 | 216 | if (needcast) { 217 | o = PyArray_Cast(oarr, new_typenum); 218 | oarr = (PyArrayObject*) o; 219 | } else { 220 | oarr = PyArray_GETCONTIGUOUS(oarr); 221 | o = (PyObject*) oarr; 222 | } 223 | 224 | _strides = PyArray_STRIDES(oarr); 225 | } 226 | 227 | for (int i = 0; i < ndims; i++) { 228 | size[i] = (int) _sizes[i]; 229 | step[i] = (size_t) _strides[i]; 230 | } 231 | 232 | // handle degenerate case 233 | if (ndims == 0) { 234 | size[ndims] = 1; 235 | step[ndims] = elemsize; 236 | ndims++; 237 | } 238 | 239 | if (ismultichannel) { 240 | ndims--; 241 | type |= CV_MAKETYPE(0, size[2]); 242 | } 243 | 244 | if (ndims > 2 && !allowND) { 245 | failmsg("%s has more than 2 dimensions"); 246 | } else { 247 | 248 | m = Mat(ndims, size, type, PyArray_DATA(oarr), step); 249 | m.u = g_numpyAllocator.allocate(o, ndims, size, type, step); 250 | m.addref(); 251 | 252 | if (!needcopy) { 253 | Py_INCREF(o); 254 | } 255 | } 256 | m.allocator = &g_numpyAllocator; 257 | } 258 | return m; 259 | } 260 | 261 | //=================== BOOST CONVERTERS ======================================================= 262 | 263 | PyObject* matToNDArrayBoostConverter::convert(Mat const& m) { 264 | if (!m.data) 265 | Py_RETURN_NONE; 266 | Mat temp, 267 | *p = (Mat*) &m; 268 | if (!p->u || p->allocator != &g_numpyAllocator) 269 | { 270 | temp.allocator = &g_numpyAllocator; 271 | ERRWRAP2(m.copyTo(temp)); 272 | p = &temp; 273 | } 274 | PyObject* o = (PyObject*) p->u->userdata; 275 | Py_INCREF(o); 276 | return o; 277 | } 278 | 279 | matFromNDArrayBoostConverter::matFromNDArrayBoostConverter() { 280 | boost::python::converter::registry::push_back(convertible, construct, 281 | boost::python::type_id()); 282 | } 283 | 284 | /// @brief Check if PyObject is an array and can be converted to OpenCV matrix. 285 | void* matFromNDArrayBoostConverter::convertible(PyObject* object) { 286 | if (!PyArray_Check(object)) { 287 | return NULL; 288 | } 289 | #ifndef CV_MAX_DIM 290 | const int CV_MAX_DIM = 32; 291 | #endif 292 | PyArrayObject* oarr = (PyArrayObject*) object; 293 | 294 | int typenum = PyArray_TYPE(oarr); 295 | if (typenum != NPY_INT64 && typenum != NPY_UINT64 && typenum != NPY_LONG 296 | && typenum != NPY_UBYTE && typenum != NPY_BYTE 297 | && typenum != NPY_USHORT && typenum != NPY_SHORT 298 | && typenum != NPY_INT && typenum != NPY_INT32 299 | && typenum != NPY_FLOAT && typenum != NPY_DOUBLE) { 300 | return NULL; 301 | } 302 | int ndims = PyArray_NDIM(oarr); //data type not supported 303 | 304 | if (ndims >= CV_MAX_DIM) { 305 | return NULL; //too many dimensions 306 | } 307 | return object; 308 | } 309 | 310 | /// @brief Construct a Mat from an NDArray object. 311 | void matFromNDArrayBoostConverter::construct(PyObject* object, 312 | boost::python::converter::rvalue_from_python_stage1_data* data) { 313 | namespace python = boost::python; 314 | // Object is a borrowed reference, so create a handle indicting it is 315 | // borrowed for proper reference counting. 316 | python::handle<> handle(python::borrowed(object)); 317 | 318 | // Obtain a handle to the memory block that the converter has allocated 319 | // for the C++ type. 320 | typedef python::converter::rvalue_from_python_storage storage_type; 321 | void* storage = reinterpret_cast(data)->storage.bytes; 322 | 323 | // Allocate the C++ type into the converter's memory block, and assign 324 | // its handle to the converter's convertible variable. The C++ 325 | // container is populated by passing the begin and end iterators of 326 | // the python object to the container's constructor. 327 | PyArrayObject* oarr = (PyArrayObject*) object; 328 | 329 | bool needcopy = false, needcast = false; 330 | int typenum = PyArray_TYPE(oarr), new_typenum = typenum; 331 | int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S : 332 | typenum == NPY_USHORT ? CV_16U : 333 | typenum == NPY_SHORT ? CV_16S : 334 | typenum == NPY_INT ? CV_32S : 335 | typenum == NPY_INT32 ? CV_32S : 336 | typenum == NPY_FLOAT ? CV_32F : 337 | typenum == NPY_DOUBLE ? CV_64F : -1; 338 | 339 | if (type < 0) { 340 | needcopy = needcast = true; 341 | new_typenum = NPY_INT; 342 | type = CV_32S; 343 | } 344 | 345 | #ifndef CV_MAX_DIM 346 | const int CV_MAX_DIM = 32; 347 | #endif 348 | int ndims = PyArray_NDIM(oarr); 349 | 350 | int size[CV_MAX_DIM + 1]; 351 | size_t step[CV_MAX_DIM + 1]; 352 | size_t elemsize = CV_ELEM_SIZE1(type); 353 | const npy_intp* _sizes = PyArray_DIMS(oarr); 354 | const npy_intp* _strides = PyArray_STRIDES(oarr); 355 | bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX; 356 | 357 | for (int i = ndims - 1; i >= 0 && !needcopy; i--) { 358 | // these checks handle cases of 359 | // a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases 360 | // b) transposed arrays, where _strides[] elements go in non-descending order 361 | // c) flipped arrays, where some of _strides[] elements are negative 362 | if ((i == ndims - 1 && (size_t) _strides[i] != elemsize) 363 | || (i < ndims - 1 && _strides[i] < _strides[i + 1])) 364 | needcopy = true; 365 | } 366 | 367 | if (ismultichannel && _strides[1] != (npy_intp) elemsize * _sizes[2]) 368 | needcopy = true; 369 | 370 | if (needcopy) { 371 | 372 | if (needcast) { 373 | object = PyArray_Cast(oarr, new_typenum); 374 | oarr = (PyArrayObject*) object; 375 | } else { 376 | oarr = PyArray_GETCONTIGUOUS(oarr); 377 | object = (PyObject*) oarr; 378 | } 379 | 380 | _strides = PyArray_STRIDES(oarr); 381 | } 382 | 383 | for (int i = 0; i < ndims; i++) { 384 | size[i] = (int) _sizes[i]; 385 | step[i] = (size_t) _strides[i]; 386 | } 387 | 388 | // handle degenerate case 389 | if (ndims == 0) { 390 | size[ndims] = 1; 391 | step[ndims] = elemsize; 392 | ndims++; 393 | } 394 | 395 | if (ismultichannel) { 396 | ndims--; 397 | type |= CV_MAKETYPE(0, size[2]); 398 | } 399 | if (!needcopy) { 400 | Py_INCREF(object); 401 | } 402 | 403 | cv::Mat* m = new (storage) cv::Mat(ndims, size, type, PyArray_DATA(oarr), step); 404 | m->u = g_numpyAllocator.allocate(object, ndims, size, type, step); 405 | m->allocator = &g_numpyAllocator; 406 | m->addref(); 407 | data->convertible = storage; 408 | } 409 | 410 | } //end namespace pbcvt 411 | #endif 412 | -------------------------------------------------------------------------------- /pyboostcvconverter/pyboostcvconverter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CVBoostConverter.hpp 3 | * 4 | * Created on: Mar 20, 2014 5 | * Author: Gregory Kramida 6 | * Copyright: (c) 2014 Gregory Kramida 7 | * License: MIT 8 | */ 9 | 10 | #ifndef CVBOOSTCONVERTER_HPP_ 11 | #define CVBOOSTCONVERTER_HPP_ 12 | 13 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace pbcvt{ 21 | 22 | using namespace cv; 23 | 24 | 25 | static PyObject* opencv_error = 0; 26 | 27 | 28 | //=================== MACROS ================================================================= 29 | #define ERRWRAP2(expr) \ 30 | try \ 31 | { \ 32 | PyAllowThreads allowThreads; \ 33 | expr; \ 34 | } \ 35 | catch (const cv::Exception &e) \ 36 | { \ 37 | PyErr_SetString(opencv_error, e.what()); \ 38 | return 0; \ 39 | } 40 | 41 | //=================== ERROR HANDLING ========================================================= 42 | 43 | static int failmsg(const char *fmt, ...); 44 | 45 | //=================== THREADING ============================================================== 46 | class PyAllowThreads; 47 | class PyEnsureGIL; 48 | 49 | static size_t REFCOUNT_OFFSET = (size_t)&(((PyObject*)0)->ob_refcnt) + 50 | (0x12345678 != *(const size_t*)"\x78\x56\x34\x12\0\0\0\0\0")*sizeof(int); 51 | 52 | static inline PyObject* pyObjectFromRefcount(const int* refcount) 53 | { 54 | return (PyObject*)((size_t)refcount - REFCOUNT_OFFSET); 55 | } 56 | 57 | static inline int* refcountFromPyObject(const PyObject* obj) 58 | { 59 | return (int*)((size_t)obj + REFCOUNT_OFFSET); 60 | } 61 | 62 | //=================== NUMPY ALLOCATOR FOR OPENCV ============================================= 63 | 64 | class NumpyAllocator; 65 | 66 | //=================== STANDALONE CONVERTER FUNCTIONS ========================================= 67 | 68 | PyObject* fromMatToNDArray(const Mat& m); 69 | Mat fromNDArrayToMat(PyObject* o); 70 | 71 | //=================== BOOST CONVERTERS ======================================================= 72 | 73 | struct matToNDArrayBoostConverter { 74 | static PyObject* convert(Mat const& m); 75 | }; 76 | 77 | 78 | struct matFromNDArrayBoostConverter { 79 | 80 | matFromNDArrayBoostConverter(); 81 | 82 | /// @brief Check if PyObject is an array and can be converted to OpenCV matrix. 83 | static void* convertible(PyObject* object); 84 | 85 | /// @brief Construct a Mat from an NDArray object. 86 | static void construct(PyObject* object, 87 | boost::python::converter::rvalue_from_python_stage1_data* data); 88 | }; 89 | } // end namespace pbcvt 90 | #endif /* CVBOOSTCONVERTER_HPP_ */ 91 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Created by lucy on 2020/11/02 2 | 3 | ## Rtsp库c++API封装 4 | 封装成python可直接导入的动态链接库; 5 | rockchip_rtsp可以获取rtsp视频流并调用硬件VPU自动解码; 6 | rtsp更多资料 http://t.rock-chips.com/forum.php?mod=viewthread&tid=749&highlight=rtsp 7 | 8 | 9 | ## 操作流程 10 | 11 | 编译 make 12 | 13 | 运行示例`python3 rtsp.py` 14 | 15 | make clean 16 | 17 | ## 问题&解决 18 | 1.报错 mpp_log: decode_get_frame failed, return -8. 19 | 20 | 解决:先验证摄像头是否能拉去到视频流,如果在你的PC上可以,但是代码依然报错, 21 | 那么在板子上用cv2.VideoCapture尝试能否拉到视频流,如果报错method DESCRIBE failed: 401 Unauthorized 22 | 就重启摄像头即可 23 | -------------------------------------------------------------------------------- /rtsp.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import pbcvt 3 | ''' 4 | pbcvt封装库API 5 | 6 | Rtsp(rtsp,user,passwd) 7 | 初始化 8 | :param rtsp:rtsp流地址 9 | :param user:用户名 10 | :param passwd:密码 11 | :returns: 12 | 13 | rtsp_main() 14 | 捕获码流并初始化配置 15 | :returns: ture or false 16 | 17 | ret_to_python() 18 | :returns: NULL or NDArray 19 | 20 | close() 21 | :returns: 0 代表成功关闭 22 | ''' 23 | rtsp = pbcvt.Rtsp("rtsp://av_stream","admin","123456") 24 | print(" input parameters successfully ! ") 25 | temp = rtsp.rtsp_main() 26 | while temp: 27 | img = rtsp.ret_to_python() 28 | if img is None: 29 | print(" img null ! ") 30 | # res = rtsp.close() 31 | continue 32 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 33 | cv2.imshow("test", img) 34 | cv2.waitKey(10) 35 | --------------------------------------------------------------------------------