| #pragma once |
| |
| #include <ast_video_types.hpp> |
| #include <cassert> |
| #include <iostream> |
| #include <mutex> |
| #include <vector> |
| #include <boost/asio.hpp> |
| |
| namespace ast_video { |
| |
| // |
| // Cursor struct is used in User Mode |
| // |
| struct AstCurAttributionTag { |
| unsigned int posX; |
| unsigned int posY; |
| unsigned int curWidth; |
| unsigned int curHeight; |
| unsigned int curType; // 0:mono 1:color 2:disappear cursor |
| unsigned int curChangeFlag; |
| }; |
| |
| // |
| // For storing Cursor Information |
| // |
| struct AstCursorTag { |
| AstCurAttributionTag attr; |
| // unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2]; |
| unsigned char *icon; //[64*64*2]; |
| }; |
| |
| // |
| // For select image format, i.e. 422 JPG420, 444 JPG444, lumin/chrom table, 0 |
| // ~ 11, low to high |
| // |
| struct FeaturesTag { |
| short jpgFmt; // 422:JPG420, 444:JPG444 |
| short luminTbl; |
| short chromTbl; |
| short toleranceNoise; |
| int w; |
| int h; |
| unsigned char *buf; |
| }; |
| |
| // |
| // For configure video engine control registers |
| // |
| struct ImageInfo { |
| short doImageRefresh; // Action 0:motion 1:fullframe 2:quick cursor |
| char qcValid; // quick cursor enable/disable |
| unsigned int len; |
| int crypttype; |
| char cryptkey[16]; |
| union { |
| FeaturesTag features; |
| AstCursorTag cursorInfo; |
| } parameter; |
| }; |
| |
| class SimpleVideoPuller { |
| public: |
| SimpleVideoPuller() : imageInfo(){}; |
| |
| void initialize() { |
| std::cout << "Opening /dev/video\n"; |
| videoFd = open("/dev/video", O_RDWR); |
| if (videoFd == 0) { |
| std::cout << "Failed to open /dev/video\n"; |
| throw std::runtime_error("Failed to open /dev/video"); |
| } |
| std::cout << "Opened successfully\n"; |
| } |
| |
| RawVideoBuffer readVideo() { |
| assert(videoFd != 0); |
| RawVideoBuffer raw; |
| |
| imageInfo.doImageRefresh = 1; // full frame refresh |
| imageInfo.qcValid = 0; // quick cursor disabled |
| imageInfo.parameter.features.buf = |
| reinterpret_cast<unsigned char *>(raw.buffer.data()); |
| imageInfo.crypttype = -1; |
| std::cout << "Writing\n"; |
| |
| int status; |
| /* |
| status = write(videoFd, reinterpret_cast<char*>(&imageInfo), |
| sizeof(imageInfo)); |
| if (status != sizeof(imageInfo)) { |
| std::cout << "Write failed. Return: " << status << "\n"; |
| perror("perror output:"); |
| } |
| |
| std::cout << "Write done\n"; |
| */ |
| std::cout << "Reading\n"; |
| status = |
| read(videoFd, reinterpret_cast<char *>(&imageInfo), sizeof(imageInfo)); |
| std::cout << "Done reading\n"; |
| |
| if (status != 0) { |
| std::cerr << "Read failed with status " << status << "\n"; |
| } |
| |
| raw.buffer.resize(imageInfo.len); |
| |
| raw.height = imageInfo.parameter.features.h; |
| raw.width = imageInfo.parameter.features.w; |
| if (imageInfo.parameter.features.jpgFmt == 422) { |
| raw.mode = YuvMode::YUV420; |
| } else { |
| raw.mode = YuvMode::YUV444; |
| } |
| return raw; |
| } |
| |
| private: |
| int videoFd{}; |
| ImageInfo imageInfo; |
| }; |
| |
| #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) |
| class AsyncVideoPuller { |
| public: |
| using video_callback = std::function<void(RawVideoBuffer &)>; |
| |
| explicit AsyncVideoPuller(boost::asio::io_service &ioService) |
| : imageInfo(), devVideo(ioService, open("/dev/video", O_RDWR)) { |
| videobuf = std::make_shared<RawVideoBuffer>(); |
| |
| imageInfo.doImageRefresh = 1; // full frame refresh |
| imageInfo.qcValid = 0; // quick cursor disabled |
| imageInfo.parameter.features.buf = |
| reinterpret_cast<unsigned char *>(videobuf->buffer.data()); |
| imageInfo.crypttype = -1; |
| }; |
| |
| void registerCallback(video_callback &callback) { |
| std::lock_guard<std::mutex> lock(callbackMutex); |
| callbacks.push_back(callback); |
| startRead(); |
| } |
| |
| void startRead() { |
| auto mutableBuffer = boost::asio::buffer(&imageInfo, sizeof(imageInfo)); |
| boost::asio::async_read(devVideo, mutableBuffer, |
| [this](const boost::system::error_code &ec, |
| std::size_t bytes_transferred) { |
| if (ec) { |
| std::cerr << "Read failed with status " << ec |
| << "\n"; |
| } else { |
| this->readDone(); |
| } |
| }); |
| } |
| |
| void readDone() { |
| std::cout << "Done reading\n"; |
| videobuf->buffer.resize(imageInfo.len); |
| |
| videobuf->height = imageInfo.parameter.features.h; |
| videobuf->width = imageInfo.parameter.features.w; |
| if (imageInfo.parameter.features.jpgFmt == 422) { |
| videobuf->mode = YuvMode::YUV420; |
| } else { |
| videobuf->mode = YuvMode::YUV444; |
| } |
| std::lock_guard<std::mutex> lock(callbackMutex); |
| 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 devVideo; |
| ImageInfo imageInfo; |
| std::mutex callbackMutex; |
| std::vector<video_callback> callbacks; |
| }; |
| #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) |
| } // namespace ast_video |