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