#ifndef VIDEO_DECODER_H #define VIDEO_DECODER_H #include #include #include // Video decoder using NDK MediaCodec API // Decodes video files to YUV420 frames and writes to shared memory ring buffer // for consumption by the HAL hook in the camera provider process. namespace video_decoder { // Shared memory ring buffer header // This structure is placed at the beginning of the memfd shared memory region. struct RingBufferHeader { uint32_t magic; // 0xCAM2MAGC uint32_t version; // Header version (1) uint32_t frame_count; // Number of frame slots in ring buffer uint32_t frame_width; // Decoded frame width uint32_t frame_height; // Decoded frame height uint32_t frame_size; // Size of one YUV420 frame (w * h * 3/2) uint32_t write_index; // Atomic: next slot to write uint32_t read_index; // Atomic: last slot read by consumer uint32_t sequence; // Monotonically increasing frame counter uint32_t flags; // Bit flags (bit 0: decoder running) uint64_t last_timestamp; // Timestamp of last written frame (us) uint8_t reserved[216]; // Padding to 256 bytes }; static constexpr uint32_t RING_MAGIC = 0xCA22A61C; static constexpr uint32_t RING_VERSION = 1; static constexpr uint32_t RING_FRAME_COUNT = 4; static constexpr uint32_t RING_HEADER_SIZE = 256; static constexpr uint32_t FLAG_DECODER_RUNNING = 0x1; // Calculate total shared memory size needed inline size_t calc_shmem_size(uint32_t width, uint32_t height, uint32_t frame_count = RING_FRAME_COUNT) { size_t frame_size = (size_t)width * height * 3 / 2; // YUV420 return RING_HEADER_SIZE + (frame_size * frame_count); } // Get pointer to frame slot in shared memory inline uint8_t* get_frame_ptr(uint8_t* base, uint32_t index, uint32_t frame_size, uint32_t frame_count) { return base + RING_HEADER_SIZE + ((index % frame_count) * frame_size); } // Decoder state struct DecoderState { std::string video_path; int32_t width; int32_t height; int32_t rotation; // 0, 90, 180, 270 bool loop; bool running; // Shared memory int shmem_fd; uint8_t* shmem_base; size_t shmem_size; RingBufferHeader* header; // Decoder thread pthread_t decoder_thread; }; // Initialize the video decoder // Returns 0 on success, negative on error int init_decoder(const char* video_path, bool loop = true); // Start the decoder thread // Returns 0 on success int start_decoder(); // Stop the decoder thread void stop_decoder(); // Release decoder resources void release_decoder(); // Get the shared memory fd (for passing to other processes) // Returns -1 if not initialized int get_shmem_fd(); // Get decoder state info int get_decoder_width(); int get_decoder_height(); bool is_decoder_running(); // Write a YUV420 frame to the shared memory ring buffer // Called internally by the decoder thread // y_data, u_data, v_data: pointers to Y, U, V planes // y_stride, uv_stride: stride of Y and UV planes // width, height: frame dimensions bool write_frame_to_ring(const uint8_t* y_data, const uint8_t* u_data, const uint8_t* v_data, int y_stride, int uv_stride, int width, int height); } // namespace video_decoder #endif // VIDEO_DECODER_H