Initial commit
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#ifndef BUFFER_CONVERTER_H
|
||||
#define BUFFER_CONVERTER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
// Buffer format conversion utilities for HAL compatibility.
|
||||
// Converts between decoder output formats and HAL-expected formats.
|
||||
// Uses ARM NEON intrinsics for performance on Pixel 9a (arm64-v8a).
|
||||
|
||||
namespace buffer_converter {
|
||||
|
||||
// Convert YUV420 planar (I420) to NV21 (semi-planar, VU interleaved)
|
||||
// YUV420 planar: Y plane, U plane, V plane (separate)
|
||||
// NV21: Y plane, VU interleaved plane
|
||||
//
|
||||
// src_y, src_u, src_v: source plane pointers
|
||||
// src_y_stride, src_uv_stride: source plane strides (bytes per row)
|
||||
// dst_nv21: destination buffer (Y plane followed by VU interleaved)
|
||||
// dst_y_stride, dst_uv_stride: destination strides
|
||||
// width, height: frame dimensions
|
||||
//
|
||||
// Returns true on success, false on error
|
||||
bool yuv420_planar_to_nv21(
|
||||
const uint8_t* src_y, int src_y_stride,
|
||||
const uint8_t* src_u, int src_u_stride,
|
||||
const uint8_t* src_v, int src_v_stride,
|
||||
uint8_t* dst_nv21, int dst_y_stride, int dst_uv_stride,
|
||||
int width, int height);
|
||||
|
||||
// Convert YUV420 planar (I420) to YUV420 planar with different stride
|
||||
// Handles stride mismatch between decoder output and HAL buffer.
|
||||
// Copies Y plane with stride adjustment, then U and V planes.
|
||||
//
|
||||
// Returns true on success
|
||||
bool yuv420_planar_copy_with_stride(
|
||||
const uint8_t* src_y, int src_y_stride,
|
||||
const uint8_t* src_u, int src_u_stride,
|
||||
const uint8_t* src_v, int src_v_stride,
|
||||
uint8_t* dst_y, int dst_y_stride,
|
||||
uint8_t* dst_u, int dst_u_stride,
|
||||
uint8_t* dst_v, int dst_v_stride,
|
||||
int width, int height);
|
||||
|
||||
// Convert NV21 (semi-planar) to YUV420 planar (I420)
|
||||
// Used when decoder outputs NV21 but HAL expects planar.
|
||||
//
|
||||
// Returns true on success
|
||||
bool nv21_to_yuv420_planar(
|
||||
const uint8_t* src_nv21, int src_y_stride, int src_uv_stride,
|
||||
uint8_t* dst_y, int dst_y_stride,
|
||||
uint8_t* dst_u, int dst_u_stride,
|
||||
uint8_t* dst_v, int dst_v_stride,
|
||||
int width, int height);
|
||||
|
||||
// Fast Y plane copy with NEON (handles stride mismatch)
|
||||
// Copies width bytes per row, advancing by stride each row.
|
||||
void copy_plane_neon(
|
||||
const uint8_t* src, int src_stride,
|
||||
uint8_t* dst, int dst_stride,
|
||||
int width, int height);
|
||||
|
||||
// Interleave U and V planes into NV21 format (VU order) using NEON
|
||||
void interleave_uv_to_nv21_neon(
|
||||
const uint8_t* src_u, int src_u_stride,
|
||||
const uint8_t* src_v, int src_v_stride,
|
||||
uint8_t* dst_vu, int dst_vu_stride,
|
||||
int width, int height);
|
||||
|
||||
} // namespace buffer_converter
|
||||
|
||||
#endif // BUFFER_CONVERTER_H
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef CAMERA_HAL_ICAMERA_DEVICE_H
|
||||
#define CAMERA_HAL_ICAMERA_DEVICE_H
|
||||
|
||||
#include "types.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace camera_hal {
|
||||
|
||||
// ICameraDevice AIDL v4 interface
|
||||
// Mirrors: hardware/interfaces/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
|
||||
class ICameraDevice {
|
||||
public:
|
||||
virtual ~ICameraDevice() = default;
|
||||
|
||||
virtual int32_t open(void* callback) = 0;
|
||||
virtual int32_t openInjectionSession(void* callback) = 0;
|
||||
virtual int32_t setTorchMode(bool enabled) = 0;
|
||||
virtual int32_t dumpState(int32_t fd) = 0;
|
||||
virtual int32_t getCameraCharacteristics(void* characteristics) = 0;
|
||||
virtual int32_t getPhysicalCameraCharacteristics(
|
||||
const char* physical_camera_id,
|
||||
void* characteristics) = 0;
|
||||
virtual int32_t close() = 0;
|
||||
};
|
||||
|
||||
// Function pointer types for dlsym
|
||||
typedef int32_t (*ICameraDevice_open_t)(void* self, void* callback);
|
||||
typedef int32_t (*ICameraDevice_close_t)(void* self);
|
||||
typedef int32_t (*ICameraDevice_getCameraCharacteristics_t)(
|
||||
void* self, void* characteristics);
|
||||
|
||||
} // namespace camera_hal
|
||||
|
||||
#endif // CAMERA_HAL_ICAMERA_DEVICE_H
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef CAMERA_HAL_ICAMERA_DEVICE_SESSION_H
|
||||
#define CAMERA_HAL_ICAMERA_DEVICE_SESSION_H
|
||||
|
||||
#include "types.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace camera_hal {
|
||||
|
||||
// ICameraDeviceSession AIDL v4 interface
|
||||
// Mirrors: hardware/interfaces/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl
|
||||
class ICameraDeviceSession {
|
||||
public:
|
||||
virtual ~ICameraDeviceSession() = default;
|
||||
|
||||
virtual int32_t configureStreams(
|
||||
const Stream* streams,
|
||||
int32_t stream_count,
|
||||
StreamConfigurationMode mode,
|
||||
HalStreamConfiguration* out_config) = 0;
|
||||
|
||||
virtual int32_t processCaptureRequest(
|
||||
const CaptureRequest* requests,
|
||||
int32_t request_count,
|
||||
int32_t* out_num_request_processed) = 0;
|
||||
|
||||
virtual int32_t flush() = 0;
|
||||
virtual int32_t close() = 0;
|
||||
virtual int32_t signalStreamFlush(const int32_t* stream_ids, int32_t count) = 0;
|
||||
virtual int32_t getCaptureRequestMetadataQueue(void* queue) = 0;
|
||||
virtual int32_t getCaptureResultMetadataQueue(void* queue) = 0;
|
||||
virtual int32_t switchToOffline(
|
||||
const int32_t* streams_to_keep,
|
||||
int32_t count,
|
||||
void* out_offline_session) = 0;
|
||||
virtual int32_t isReconfigurationRequired(
|
||||
const void* old_session_params,
|
||||
const void* new_session_params,
|
||||
bool* out_required) = 0;
|
||||
};
|
||||
|
||||
// Function pointer types for dlsym
|
||||
typedef int32_t (*ICameraDeviceSession_configureStreams_t)(
|
||||
void* self,
|
||||
const Stream* streams,
|
||||
int32_t stream_count,
|
||||
StreamConfigurationMode mode,
|
||||
HalStreamConfiguration* out_config);
|
||||
|
||||
typedef int32_t (*ICameraDeviceSession_processCaptureRequest_t)(
|
||||
void* self,
|
||||
const CaptureRequest* requests,
|
||||
int32_t request_count,
|
||||
int32_t* out_num_request_processed);
|
||||
|
||||
typedef int32_t (*ICameraDeviceSession_flush_t)(void* self);
|
||||
typedef int32_t (*ICameraDeviceSession_close_t)(void* self);
|
||||
|
||||
} // namespace camera_hal
|
||||
|
||||
#endif // CAMERA_HAL_ICAMERA_DEVICE_SESSION_H
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef CAMERA_HAL_ICAMERA_PROVIDER_H
|
||||
#define CAMERA_HAL_ICAMERA_PROVIDER_H
|
||||
|
||||
#include "types.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace camera_hal {
|
||||
|
||||
// ICameraProvider AIDL v3 interface
|
||||
// Mirrors: hardware/interfaces/camera/provider/aidl/android/hardware/camera/provider/ICameraProvider.aidl
|
||||
class ICameraProvider {
|
||||
public:
|
||||
virtual ~ICameraProvider() = default;
|
||||
|
||||
virtual int32_t setCallback(void* callback) = 0;
|
||||
virtual int32_t getCameraIdList(char*** camera_ids, int32_t* count) = 0;
|
||||
virtual int32_t getCameraDeviceInterface(
|
||||
const char* camera_id,
|
||||
void** out_device) = 0;
|
||||
virtual int32_t notifyDeviceStateChange(int64_t device_state) = 0;
|
||||
virtual int32_t getConcurrentStreamingCameraIds(
|
||||
char*** camera_ids, int32_t* count) = 0;
|
||||
virtual int32_t openSession(
|
||||
const char* camera_id,
|
||||
void* callback,
|
||||
void** out_session) = 0;
|
||||
virtual int32_t getVendorTags(void* tags) = 0;
|
||||
virtual int32_t getCameraCharacteristics(
|
||||
const char* camera_id,
|
||||
void* characteristics) = 0;
|
||||
};
|
||||
|
||||
typedef int32_t (*ICameraProvider_getCameraIdList_t)(
|
||||
void* self, char*** camera_ids, int32_t* count);
|
||||
typedef int32_t (*ICameraProvider_getCameraDeviceInterface_t)(
|
||||
void* self, const char* camera_id, void** out_device);
|
||||
typedef int32_t (*ICameraProvider_openSession_t)(
|
||||
void* self, const char* camera_id, void* callback, void** out_session);
|
||||
|
||||
} // namespace camera_hal
|
||||
|
||||
#endif // CAMERA_HAL_ICAMERA_PROVIDER_H
|
||||
@@ -0,0 +1,103 @@
|
||||
#ifndef CAMERA_HAL_TYPES_H
|
||||
#define CAMERA_HAL_TYPES_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
// AIDL Camera HAL v4 common types
|
||||
// These mirror the AIDL interface types from hardware/interfaces/camera/
|
||||
|
||||
namespace camera_hal {
|
||||
|
||||
// Stream format constants (matching AIDL CameraMetadata)
|
||||
enum StreamFormat : int32_t {
|
||||
FORMAT_YUV_420_888 = 32,
|
||||
FORMAT_IMPLEMENTATION_DEFINED = 35,
|
||||
FORMAT_BLOB_JPEG = 37,
|
||||
FORMAT_RAW16 = 38,
|
||||
FORMAT_RAW_PRIVATE = 39,
|
||||
FORMAT_RAW10 = 40,
|
||||
FORMAT_RAW12 = 41,
|
||||
FORMAT_DEPTH16 = 42,
|
||||
FORMAT_DEPTH_POINT_CLOUD = 43,
|
||||
FORMAT_PRIVATE = 50,
|
||||
};
|
||||
|
||||
// Stream direction
|
||||
enum StreamDirection : int32_t {
|
||||
STREAM_OUTPUT = 0,
|
||||
STREAM_INPUT = 1,
|
||||
};
|
||||
|
||||
// Stream configuration
|
||||
struct Stream {
|
||||
int32_t id;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
StreamFormat format;
|
||||
StreamDirection direction;
|
||||
int32_t usage;
|
||||
int32_t rotation;
|
||||
int32_t data_space;
|
||||
void* physical_camera_id; // nullable
|
||||
};
|
||||
|
||||
// Buffer status
|
||||
enum BufferStatus : int32_t {
|
||||
BUFFER_STATUS_OK = 0,
|
||||
BUFFER_STATUS_ERROR = 1,
|
||||
BUFFER_STATUS_NO_BUFFER = 2,
|
||||
};
|
||||
|
||||
// Camera buffer descriptor (wraps AHardwareBuffer / GraphicBuffer)
|
||||
struct CameraBuffer {
|
||||
int32_t stream_id;
|
||||
int64_t buffer_id;
|
||||
void* handle; // AHardwareBuffer* or native_handle_t*
|
||||
int32_t status;
|
||||
int64_t timestamp;
|
||||
void* acquire_fence;
|
||||
void* release_fence;
|
||||
};
|
||||
|
||||
// Capture request
|
||||
struct CaptureRequest {
|
||||
int32_t frame_number;
|
||||
int32_t settings_count;
|
||||
void* settings; // CameraMetadata*
|
||||
int32_t input_buffer_present;
|
||||
CameraBuffer* input_buffer;
|
||||
int32_t output_buffer_count;
|
||||
CameraBuffer* output_buffers;
|
||||
int32_t physical_camera_id_count;
|
||||
void* physical_camera_ids;
|
||||
void* physical_camera_settings;
|
||||
};
|
||||
|
||||
// Capture result
|
||||
struct CaptureResult {
|
||||
int32_t frame_number;
|
||||
void* result; // CameraMetadata*
|
||||
int32_t output_buffer_count;
|
||||
CameraBuffer* output_buffers;
|
||||
int32_t physical_camera_metadata_count;
|
||||
void* physical_camera_ids;
|
||||
void* physical_camera_metadata;
|
||||
};
|
||||
|
||||
// Stream configuration mode
|
||||
enum StreamConfigurationMode : int32_t {
|
||||
NORMAL_MODE = 0,
|
||||
CONSTRAINED_HIGH_SPEED_MODE = 1,
|
||||
};
|
||||
|
||||
// HalStreamConfiguration (result of configureStreams)
|
||||
struct HalStreamConfiguration {
|
||||
int32_t stream_count;
|
||||
Stream* streams;
|
||||
StreamConfigurationMode mode;
|
||||
};
|
||||
|
||||
} // namespace camera_hal
|
||||
|
||||
#endif // CAMERA_HAL_TYPES_H
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef RTSP_CLIENT_H
|
||||
#define RTSP_CLIENT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace rtsp_client {
|
||||
|
||||
static constexpr int RTSP_DEFAULT_PORT = 554;
|
||||
static constexpr int RTP_BUFFER_SIZE = 65536;
|
||||
static constexpr int MAX_URL_LEN = 512;
|
||||
|
||||
struct RtspState {
|
||||
std::string url;
|
||||
std::string host;
|
||||
int port;
|
||||
std::string path;
|
||||
|
||||
int rtsp_fd;
|
||||
int rtp_fd;
|
||||
int rtcp_fd;
|
||||
int local_rtp_port;
|
||||
int local_rtcp_port;
|
||||
|
||||
std::string session_id;
|
||||
std::string control_url;
|
||||
std::string video_track_url;
|
||||
|
||||
bool connected;
|
||||
bool running;
|
||||
bool playing;
|
||||
|
||||
pthread_t receiver_thread;
|
||||
|
||||
int shmem_fd;
|
||||
uint8_t* shmem_base;
|
||||
size_t shmem_size;
|
||||
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
|
||||
uint32_t frame_count;
|
||||
uint64_t bytes_received;
|
||||
};
|
||||
|
||||
int init_rtsp(const char* url);
|
||||
int connect_rtsp();
|
||||
int play_rtsp();
|
||||
void stop_rtsp();
|
||||
void release_rtsp();
|
||||
bool is_rtsp_connected();
|
||||
int get_rtsp_shmem_fd();
|
||||
int get_rtsp_width();
|
||||
int get_rtsp_height();
|
||||
|
||||
} // namespace rtsp_client
|
||||
|
||||
#endif // RTSP_CLIENT_H
|
||||
@@ -0,0 +1,100 @@
|
||||
#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();
|
||||
|
||||
// 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
|
||||
Reference in New Issue
Block a user