Files

105 lines
3.4 KiB
C++

#ifndef VIDEO_DECODER_H
#define VIDEO_DECODER_H
#include <cstdint>
#include <cstddef>
#include <string>
// 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();
// Get the shared memory base pointer (for reading frames)
// Returns nullptr if not initialized
uint8_t* get_shmem_base();
// 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