Created
May 28, 2025 10:31
-
-
Save gzh/68d3aecbbb12aab923a3017593efbdfb to your computer and use it in GitHub Desktop.
a raw video source example for viinex
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <functional> | |
| #include <fstream> | |
| #include <cstdlib> | |
| #include <mutex> | |
| #include <chrono> | |
| #include <thread> | |
| #include <memory> | |
| #include <vnxvideo/vnxvideo.h> | |
| void log_handler(void* usrptr, ELogLevel level, const char* subsystem, const char* message) { | |
| std::cerr << level << " " << subsystem << " " << message << std::endl; | |
| } | |
| // for brevity let's declare a type for closures | |
| typedef std::function<void(void)> TAction; | |
| // helper to pass c++ closures as vnxvideo_action_t and usrptr | |
| void invokeClosureCdecl(void* usrptr) { | |
| TAction* pAction = reinterpret_cast<TAction*>(usrptr); | |
| try { | |
| (*pAction)(); | |
| } | |
| catch (...) { | |
| std::cerr << "Uncaught exception" << std::endl; | |
| } | |
| } | |
| void checkVnxvideoRes(int res, const char* msg) { | |
| if (res != vnxvideo_err_ok) { | |
| throw std::runtime_error(msg); | |
| } | |
| } | |
| // return a shared ptr which properly releases the undelying void* pointer | |
| // this can be be used with vnxvideo_allocator_t, vnxvideo_raw_sample_t, vnxvideo_rawproc_t etc | |
| template <typename T, void ReleaseFun(T)> | |
| std::shared_ptr<void> wrapVnxvideoPtr(T t) { | |
| return std::shared_ptr<void>(t.ptr, [](void* p) {ReleaseFun(T{ p }); }); | |
| } | |
| typedef std::shared_ptr<void> PAllocator; | |
| typedef std::shared_ptr<void> PRawProc; | |
| typedef std::shared_ptr<void> PSample; | |
| // wrappers to handle vnxvideo allocator type in C++: | |
| PAllocator DuplicateShmAllocatorPtr() { | |
| vnxvideo_allocator_t allocator; | |
| vnxvideo_shm_allocator_duplicate(&allocator); | |
| //return PAllocator(allocator.ptr, [](void* p) {vnxvideo_shm_allocator_free(vnxvideo_allocator_t{ p }); }); | |
| return wrapVnxvideoPtr<vnxvideo_allocator_t, vnxvideo_shm_allocator_free>(allocator); | |
| } | |
| // a couple of C++ helpers to wrap plain C functions exported from vnxvideo lib | |
| void WithShmAllocatorStr(const char* name, int maxSizeMB, TAction action) { | |
| int res = vnxvideo_with_shm_allocator_str(name, maxSizeMB, invokeClosureCdecl, reinterpret_cast<void*>(&action)); | |
| checkVnxvideoRes(res, "vnxvideo_with_shm_allocator_str failed"); | |
| } | |
| void WithShmAllocatorPtr(PAllocator pAllocator, TAction action) { | |
| vnxvideo_allocator_t allocator{ pAllocator.get() }; | |
| int res = vnxvideo_with_shm_allocator_ptr(allocator, invokeClosureCdecl, reinterpret_cast<void*>(&action)); | |
| checkVnxvideoRes(res, "vnxvideo_with_shm_allocator_ptr failed"); | |
| } | |
| int main(int argc, char** argv) { | |
| try { | |
| int res = vnxvideo_init(log_handler, 0, VNXLOG_DEBUG); | |
| checkVnxvideoRes(res, "vnxvideo_init failed"); | |
| const char* rendezvousPoint = (argc>1)?argv[1]:"TestRawSrc1"; | |
| const int shmApertureMb = 64; | |
| PAllocator shmAllocator; | |
| PRawProc localProducer; | |
| WithShmAllocatorStr(rendezvousPoint, shmApertureMb, [&]() { | |
| vnxvideo_rawproc_t rp; | |
| res = vnxvideo_local_server_create(rendezvousPoint, shmApertureMb, &rp); | |
| if (res != vnxvideo_err_ok) | |
| return; // cannot throw exceptions here because this is enclosed with Cdecl helper functions | |
| localProducer = wrapVnxvideoPtr<vnxvideo_rawproc_t, vnxvideo_rawproc_free> (rp); | |
| shmAllocator = DuplicateShmAllocatorPtr(); | |
| }); | |
| checkVnxvideoRes(res, "vnxvideo_local_server_create failed"); | |
| const ERawMediaFormat format = EMF_I420; | |
| const int width = 2688; | |
| const int height = 1520; | |
| // set format before sending any frames; set it again when color format or resolution changes | |
| res = vnxvideo_rawproc_set_format(vnxvideo_rawproc_t{ localProducer.get() }, format, width, height); | |
| checkVnxvideoRes(res, "vnxvideo_rawproc_set_format failed"); | |
| int frameNumber = 0; | |
| for (;;) { | |
| PSample sample; | |
| WithShmAllocatorPtr(shmAllocator, [&]() { | |
| vnxvideo_raw_sample_t s; | |
| // allocate the sample within shared memory pool | |
| res = vnxvideo_raw_sample_allocate(format, width, height, &s); | |
| if (res != vnxvideo_err_ok) | |
| return; // cannot throw exceptions here | |
| sample = wrapVnxvideoPtr<vnxvideo_raw_sample_t, vnxvideo_raw_sample_free>(s); | |
| }); | |
| checkVnxvideoRes(res, "vnxvideo_raw_sample_allocate failed"); | |
| // populate the sample memory with data | |
| int strides[4]; | |
| uint8_t* planes[4]; | |
| res = vnxvideo_raw_sample_get_data(vnxvideo_raw_sample_t{ sample.get() }, strides, planes); | |
| checkVnxvideoRes(res, "vnxvideo_raw_sample_get_data failed"); | |
| // the code for filling the data depends on format (color planes layout) | |
| for (int y = 0; y < height; ++y) { | |
| uint8_t* lineOffsetY = planes[0] + y * strides[0]; | |
| uint8_t* lineOffsetU = planes[1] + (y/2) * strides[1]; | |
| uint8_t* lineOffsetV = planes[2] + (y/2) * strides[2]; | |
| for (int x = 0; x < width; ++x) { | |
| lineOffsetY[x] = x + y + frameNumber; | |
| } | |
| for (int x = 0; x < width/2; ++x) { | |
| lineOffsetU[x] = x - y + frameNumber/2; | |
| lineOffsetV[x] = y - x + frameNumber/2; | |
| } | |
| } | |
| frameNumber++; | |
| // in real app frame timestamp should be the number of milliseconds elapsed since UNIX epoch, in UTC tz. | |
| // here we assume we start with epoch, incrementing by 40 ms every frame (25 fps). | |
| uint64_t timestamp = frameNumber * 40; | |
| // this sends the frame into local transport | |
| res = vnxvideo_rawproc_process(vnxvideo_rawproc_t{ localProducer.get() }, vnxvideo_raw_sample_t{ sample.get() }, timestamp); | |
| checkVnxvideoRes(res, "vnxvideo_rawproc_process failed"); | |
| std::this_thread::sleep_for(std::chrono::milliseconds(40)); | |
| } | |
| return 0; | |
| } | |
| catch (const std::exception& e) { | |
| std::cerr << "Caught exception in main: " << e.what() << std::endl; | |
| return 1; | |
| } | |
| } |
Comments are disabled for this gist.