Loading...
Searching...
No Matches
LibavStreamInput.hpp
1#pragma once
2#include <Media/Libav.hpp>
3#if SCORE_HAS_LIBAV
4
5#include <Video/ExternalInput.hpp>
6#include <Video/FrameQueue.hpp>
7#include <Video/Rescale.hpp>
8
9extern "C" {
10#include <libavformat/avformat.h>
11#include <libswresample/swresample.h>
12}
13
14#include <ossia/detail/pod_vector.hpp>
15
16#include <score_plugin_media_export.h>
17
18#include <atomic>
19#include <chrono>
20#include <map>
21#include <string>
22#include <thread>
23#include <vector>
24
25namespace Video
26{
27
28// Lock-free ring buffer for audio, shared between decoder thread and audio engine.
29// Same design as Gfx::GStreamer::gstreamer_pipeline::AudioBuffer.
30// FIXME use a proper one, not this shit.
31struct SCORE_PLUGIN_MEDIA_EXPORT AudioRingBuffer
32{
33 int sample_rate{48000};
34 int num_channels{2};
35
36 static constexpr std::size_t ring_size = 65536;
37 std::vector<std::vector<float>> ring; // [channel][ring_size]
38 std::atomic<std::size_t> write_pos{0};
39 std::atomic<std::size_t> read_pos{0};
40
41 // Set by the audio parameter to point at its backing storage
42 std::vector<ossia::float_vector>* output_data{};
43
44 void init(int nchannels);
45 void write_planar(float** data, int num_samples, int channels);
46 void write_interleaved_float(const float* data, int num_samples, int channels);
47 void write_interleaved_s16(const int16_t* data, int num_samples, int channels);
48 void read_into_output(int block_size);
49};
50
51// Demuxes any URL/file/device via avformat, decoding both video and audio.
52// Video frames go into a FrameQueue (standard ExternalInput pattern).
53// Audio samples go into an AudioRingBuffer for the audio engine.
54class SCORE_PLUGIN_MEDIA_EXPORT LibavStreamInput final
55 : public ExternalInput
56 , public LibAVDecoder
57{
58public:
59 LibavStreamInput() noexcept;
60 ~LibavStreamInput() noexcept;
61
62 bool load(const std::string& url) noexcept;
63 bool load(
64 const std::string& url,
65 const std::map<std::string, std::string>& options) noexcept;
66
67 // Open the format context and discover streams (populates width/height/etc).
68 // Keeps the context alive for later start().
69 bool probe() noexcept;
70
71 bool start() noexcept override;
72 void stop() noexcept override;
73
74 AVFrame* dequeue_frame() noexcept override;
75 void release_frame(AVFrame* frame) noexcept override;
76
77 bool has_audio() const noexcept { return m_audioStream != nullptr; }
78 AudioRingBuffer& audio_buffer() noexcept { return m_audioBuf; }
79 const std::string& url() const noexcept { return m_url; }
80
81private:
82 void buffer_thread() noexcept;
83 void close_file() noexcept;
84 bool open_streams() noexcept;
85 void close_streams() noexcept;
86 void decode_audio_packet(AVPacket& packet) noexcept;
87
88 std::string m_url;
89 std::map<std::string, std::string> m_options;
90
91 // Audio decoding state
92 AVStream* m_audioStream{};
93 const AVCodec* m_audioCodec{};
94 AVCodecContext* m_audioCodecContext{};
95 AVFrame* m_audioFrame{};
96 AudioRingBuffer m_audioBuf;
97
98 std::thread m_thread;
99 std::atomic_bool m_running{};
100
101 // Looping: -1 = infinite, 0 = no loop, >0 = N remaining loops.
102 // Extracted from the "loop" key in options (not passed to FFmpeg).
103 int m_loop{0};
104
105 // True for file-based sources that need producer-side frame pacing.
106 // False for real-time sources (network, devices, lavfi) where I/O naturally paces.
107 bool m_needsPacing{false};
108};
109
110}
111#endif
Definition ExternalInput.hpp:11
Definition LibavStreamInput.hpp:57
Definition LibavStreamInput.hpp:32
Definition Rescale.hpp:47