mirror of
https://github.com/Cuteminded/jellyframe.git
synced 2026-10-27 00:00:47 +01:00
133 lines
4.3 KiB
C++
133 lines
4.3 KiB
C++
#pragma once
|
|
|
|
#include "video_plane.h"
|
|
|
|
#include <godot_cpp/variant/packed_byte_array.hpp>
|
|
#include <godot_cpp/variant/dictionary.hpp>
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <condition_variable>
|
|
#include <deque>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
struct AVFormatContext;
|
|
struct AVCodecContext;
|
|
struct AVFrame;
|
|
struct AVPacket;
|
|
struct SwsContext;
|
|
|
|
struct VideoPlanes {
|
|
int width = 0;
|
|
int height = 0;
|
|
int storage_width = 0;
|
|
int storage_height = 0;
|
|
int display_width = 0;
|
|
int display_height = 0;
|
|
int rotation = 0;
|
|
int plane_count = 3;
|
|
int sample_bytes = 2;
|
|
bool interleaved = false;
|
|
float sample_scale = 65535;
|
|
float code_max = 1023;
|
|
int64_t timestamp = 0;
|
|
uint64_t generation = 0;
|
|
float kr = 0.2126f;
|
|
float kb = 0.0722f;
|
|
float full_range = 0;
|
|
float transfer = 0;
|
|
float source_peak = 1000.f / 203.f;
|
|
std::array<VideoPlane, 3> planes;
|
|
};
|
|
|
|
class VideoDecoder {
|
|
public:
|
|
~VideoDecoder();
|
|
int start(const std::string &url, const std::string &authorization, int64_t start_ms);
|
|
void stop();
|
|
void set_clock(int64_t milliseconds);
|
|
void seek(int64_t milliseconds);
|
|
bool take_frame(VideoPlanes &frame);
|
|
int error() const { return decode_error; }
|
|
bool has_audio() const { return audio; }
|
|
int width() const { return source_width; }
|
|
int height() const { return source_height; }
|
|
int64_t duration_ms() const { return duration; }
|
|
bool ended() const { return end_of_stream; }
|
|
bool read_ahead_ready() const {
|
|
return reader_ended || buffered_ms >= 1000 || buffered_bytes >= 128 * 1048576 || buffered_packets >= 512;
|
|
}
|
|
godot::Dictionary diagnostics() const;
|
|
void set_frame_callback(void (*callback)(void *), void *owner) { frame_callback = callback; frame_owner = owner; }
|
|
bool has_frame();
|
|
uint64_t current_generation() const { return generation; }
|
|
|
|
private:
|
|
static int interrupt(void *owner);
|
|
void configure_hardware(const struct AVCodec *decoder);
|
|
int open(const std::string &url, const std::string &authorization);
|
|
int read_geometry();
|
|
void decode_loop();
|
|
void read_loop();
|
|
bool read_packet(AVPacket *packet, uint64_t &packet_generation, bool &flush, int &error);
|
|
void clear_packets();
|
|
void update_buffer_size();
|
|
bool publish(AVFrame *frame, uint64_t frame_generation);
|
|
bool convert(AVFrame *frame, VideoPlanes &output);
|
|
bool prepare_planes(AVFrame *frame, VideoPlanes &output, int storage_width, int storage_height);
|
|
bool download_planes(AVFrame *frame, VideoPlanes &output);
|
|
void close();
|
|
AVFormatContext *input = nullptr;
|
|
AVCodecContext *codec = nullptr;
|
|
SwsContext *scaler = nullptr;
|
|
int stream_index = -1;
|
|
int hardware_format = -1;
|
|
bool hardware_attempted = false;
|
|
int source_width = 0;
|
|
int source_height = 0;
|
|
int rotation = 0;
|
|
bool audio = false;
|
|
std::string codec_name;
|
|
std::string hardware_device;
|
|
std::atomic<uint64_t> corrupt_packets{0};
|
|
std::atomic<bool> hardware_active{false};
|
|
std::atomic<bool> pinned_download{false};
|
|
std::atomic<int> active_transfer{0};
|
|
std::atomic<uint64_t> decoded_frames{0}, dropped_frames{0}, converted_frames{0};
|
|
std::atomic<uint64_t> download_us{0}, conversion_us{0};
|
|
std::atomic<uint64_t> read_us{0}, decode_us{0}, read_bytes{0};
|
|
std::atomic<int64_t> buffered_ms{0};
|
|
std::atomic<uint64_t> buffered_bytes{0};
|
|
std::atomic<size_t> buffered_packets{0};
|
|
std::atomic<bool> reader_ended{false}, seek_interrupt{false};
|
|
int64_t origin_us = 0;
|
|
int64_t duration = 0;
|
|
std::atomic<bool> end_of_stream{false};
|
|
std::thread worker;
|
|
std::thread reader;
|
|
std::atomic<bool> stopping{false};
|
|
std::atomic<int> decode_error{0};
|
|
std::atomic<int64_t> io_deadline{0};
|
|
std::mutex mutex;
|
|
std::condition_variable wake;
|
|
struct QueuedPacket {
|
|
AVPacket *packet = nullptr;
|
|
uint64_t generation = 0;
|
|
bool flush = false;
|
|
int error = 0;
|
|
};
|
|
std::deque<QueuedPacket> packets;
|
|
VideoPlanes pending;
|
|
VideoPlanes staging;
|
|
bool frame_ready = false;
|
|
int64_t clock = 0;
|
|
int64_t seek_target = -1;
|
|
int64_t discard_before = -1;
|
|
int64_t last_publish_us = 0;
|
|
std::atomic<int64_t> decoded_timestamp{0};
|
|
std::atomic<uint64_t> generation{0};
|
|
void (*frame_callback)(void *) = nullptr;
|
|
void *frame_owner = nullptr;
|
|
};
|