| #pragma once |
| |
| #include <assert.h> |
| #include <ast_video_types.hpp> |
| #include <iostream> |
| #include <mutex> |
| #include <vector> |
| #include <boost/asio.hpp> |
| |
| namespace AstVideo { |
| |
| // |
| // Cursor struct is used in User Mode |
| // |
| typedef struct _cursor_attribution_tag { |
| unsigned int posX; |
| unsigned int posY; |
| unsigned int cur_width; |
| unsigned int cur_height; |
| unsigned int cur_type; // 0:mono 1:color 2:disappear cursor |
| unsigned int cur_change_flag; |
| } AST_CUR_ATTRIBUTION_TAG; |
| |
| // |
| // For storing Cursor Information |
| // |
| typedef struct _cursor_tag { |
| AST_CUR_ATTRIBUTION_TAG attr; |
| // unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2]; |
| unsigned char *icon; //[64*64*2]; |
| } AST_CURSOR_TAG; |
| |
| // |
| // For select image format, i.e. 422 JPG420, 444 JPG444, lumin/chrom table, 0 |
| // ~ 11, low to high |
| // |
| typedef struct _video_features { |
| short jpg_fmt; // 422:JPG420, 444:JPG444 |
| short lumin_tbl; |
| short chrom_tbl; |
| short tolerance_noise; |
| int w; |
| int h; |
| unsigned char *buf; |
| } FEATURES_TAG; |
| |
| // |
| // For configure video engine control registers |
| // |
| typedef struct _image_info { |
| short do_image_refresh; // Action 0:motion 1:fullframe 2:quick cursor |
| char qc_valid; // quick cursor enable/disable |
| unsigned int len; |
| int crypttype; |
| char cryptkey[16]; |
| union { |
| FEATURES_TAG features; |
| AST_CURSOR_TAG cursor_info; |
| } parameter; |
| } IMAGE_INFO; |
| |
| class SimpleVideoPuller { |
| public: |
| SimpleVideoPuller() : image_info(){}; |
| |
| void initialize() { |
| std::cout << "Opening /dev/video\n"; |
| video_fd = open("/dev/video", O_RDWR); |
| if (!video_fd) { |
| std::cout << "Failed to open /dev/video\n"; |
| throw std::runtime_error("Failed to open /dev/video"); |
| } |
| std::cout << "Opened successfully\n"; |
| } |
| |
| RawVideoBuffer read_video() { |
| assert(video_fd != 0); |
| RawVideoBuffer raw; |
| |
| image_info.do_image_refresh = 1; // full frame refresh |
| image_info.qc_valid = 0; // quick cursor disabled |
| image_info.parameter.features.buf = |
| reinterpret_cast<unsigned char *>(raw.buffer.data()); |
| image_info.crypttype = -1; |
| std::cout << "Writing\n"; |
| |
| int status; |
| /* |
| status = write(video_fd, reinterpret_cast<char*>(&image_info), |
| sizeof(image_info)); |
| if (status != sizeof(image_info)) { |
| std::cout << "Write failed. Return: " << status << "\n"; |
| perror("perror output:"); |
| } |
| |
| std::cout << "Write done\n"; |
| */ |
| std::cout << "Reading\n"; |
| status = read(video_fd, reinterpret_cast<char *>(&image_info), |
| sizeof(image_info)); |
| std::cout << "Done reading\n"; |
| |
| if (status != 0) { |
| std::cerr << "Read failed with status " << status << "\n"; |
| } |
| |
| raw.buffer.resize(image_info.len); |
| |
| raw.height = image_info.parameter.features.h; |
| raw.width = image_info.parameter.features.w; |
| if (image_info.parameter.features.jpg_fmt == 422) { |
| raw.mode = YuvMode::YUV420; |
| } else { |
| raw.mode = YuvMode::YUV444; |
| } |
| return raw; |
| } |
| |
| private: |
| int video_fd; |
| IMAGE_INFO image_info; |
| }; |
| |
| #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) |
| class AsyncVideoPuller { |
| public: |
| typedef std::function<void(RawVideoBuffer &)> video_callback; |
| |
| AsyncVideoPuller(boost::asio::io_service &io_service) |
| : image_info(), dev_video(io_service, open("/dev/video", O_RDWR)) { |
| videobuf = std::make_shared<RawVideoBuffer>(); |
| |
| image_info.do_image_refresh = 1; // full frame refresh |
| image_info.qc_valid = 0; // quick cursor disabled |
| image_info.parameter.features.buf = |
| reinterpret_cast<unsigned char *>(videobuf->buffer.data()); |
| image_info.crypttype = -1; |
| }; |
| |
| void register_callback(video_callback &callback) { |
| std::lock_guard<std::mutex> lock(callback_mutex); |
| callbacks.push_back(callback); |
| start_read(); |
| } |
| |
| void start_read() { |
| auto mutable_buffer = boost::asio::buffer(&image_info, sizeof(image_info)); |
| boost::asio::async_read( |
| dev_video, mutable_buffer, [this](const boost::system::error_code &ec, |
| std::size_t bytes_transferred) { |
| if (ec) { |
| std::cerr << "Read failed with status " << ec << "\n"; |
| } else { |
| this->read_done(); |
| } |
| }); |
| } |
| |
| void read_done() { |
| std::cout << "Done reading\n"; |
| videobuf->buffer.resize(image_info.len); |
| |
| videobuf->height = image_info.parameter.features.h; |
| videobuf->width = image_info.parameter.features.w; |
| if (image_info.parameter.features.jpg_fmt == 422) { |
| videobuf->mode = YuvMode::YUV420; |
| } else { |
| videobuf->mode = YuvMode::YUV444; |
| } |
| std::lock_guard<std::mutex> lock(callback_mutex); |
| for (auto &callback : callbacks) { |
| // TODO(ed) call callbacks async and double buffer frames |
| callback(*videobuf); |
| } |
| } |
| |
| private: |
| std::shared_ptr<RawVideoBuffer> videobuf; |
| boost::asio::posix::stream_descriptor dev_video; |
| IMAGE_INFO image_info; |
| std::mutex callback_mutex; |
| std::vector<video_callback> callbacks; |
| }; |
| #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) |
| } |