2 #include <ossia/detail/config.hpp>
4 #include <ossia/audio/audio_parameter.hpp>
5 #include <ossia/dataflow/audio_stretch_mode.hpp>
6 #include <ossia/dataflow/graph_node.hpp>
7 #include <ossia/dataflow/nodes/media.hpp>
8 #include <ossia/dataflow/nodes/sound.hpp>
9 #include <ossia/dataflow/port.hpp>
10 #include <ossia/detail/libav.hpp>
11 #include <ossia/detail/pod_vector.hpp>
13 #include <type_traits>
16 #include <libavcodec/avcodec.h>
17 #include <libavformat/avformat.h>
18 #include <libavutil/frame.h>
19 #include <libavutil/mem.h>
20 #include <libswresample/swresample.h>
23 namespace ossia::nodes
25 class sound_libav final :
public ossia::sound_node
32 : packet{av_packet_alloc()}
33 , frame{av_frame_alloc()}
35 m_outlets.push_back(&audio_out);
42 av_frame_free(&frame);
43 av_packet_free(&packet);
46 void set_start(std::size_t v) { start = v; }
48 void set_upmix(std::size_t v) { upmix = v; }
50 void set_sound(libav_handle hdl)
54 m_handle = std::move(hdl);
57 m_channel_q = boost::circular_buffer<float>(8192 * m_handle.channels());
60 void transport(time_value flicks)
override
64 m_handle.format, m_handle.codec, m_handle.stream, flicks.impl, AVSEEK_FLAG_ANY);
67 void fetch_from_libav(
int samples_to_write)
69 const std::size_t channels = this->channels();
73 auto floats_to_write = channels * samples_to_write;
74 while(m_channel_q.size() < floats_to_write)
77 if(m_channel_q.capacity() < 4 * floats_to_write)
79 m_channel_q.set_capacity(4 * floats_to_write);
83 auto fmt_ctx = m_handle.format;
84 auto codec_ctx = m_handle.codec;
85 auto stream = m_handle.stream;
89 av_packet_unref(packet);
90 ret = av_read_frame(fmt_ctx, packet);
92 while(ret >= 0 && ret != AVERROR(EOF) && packet->stream_index != stream->index)
94 av_packet_unref(packet);
95 ret = av_read_frame(fmt_ctx, packet);
97 if(ret == AVERROR(EOF))
107 ret = avcodec_send_packet(codec_ctx, packet);
110 ret = avcodec_receive_frame(codec_ctx, frame);
113 const int samples = frame->nb_samples;
114 m_tmp.resize(samples * channels, boost::container::default_init);
115 float* out_ptr = m_tmp.data();
116 const int read_samples = swr_convert(
117 m_handle.resample, (uint8_t**)&out_ptr, samples,
118 (
const uint8_t**)frame->extended_data, samples);
121 m_channel_q.end(), out_ptr, out_ptr + read_samples * channels);
128 template <
typename T>
130 fetch_audio(int64_t start, int64_t samples_to_write, T** audio_array_base) noexcept
132 const std::size_t channels = this->channels();
136 fetch_from_libav(samples_to_write);
139 for(
int k = 0; k < samples_to_write; k++)
141 for(std::size_t chan = 0; chan < channels; chan++)
143 if(m_channel_q.size() > 0)
145 audio_array_base[chan][k] = m_channel_q.front();
146 m_channel_q.pop_front();
150 audio_array_base[chan][k] = 0.;
156 void run(
const ossia::token_request& t, ossia::exec_state_facade e) noexcept
override
165 const auto channels = m_handle.channels();
166 const auto len = m_handle.totalPCMFrameCount();
168 ossia::audio_port& ap = *audio_out;
169 ap.set_channels(
std::max((std::size_t)upmix, (std::size_t)channels));
171 const auto [samples_to_read, samples_to_write]
172 = snd::sample_info(e.bufferSize(), e.modelToSamples(), t);
173 if(samples_to_write <= 0)
176 assert(samples_to_write > 0);
178 const auto samples_offset = t.physical_start(e.modelToSamples());
181 if(t.prev_date < m_prev_date)
186 if(t.prev_date != 0_tv)
188 transport(t.prev_date);
198 transport(t.prev_date);
202 for(std::size_t chan = 0; chan < channels; chan++)
204 ap.channel(chan).resize(e.bufferSize());
207 double stretch_ratio = update_stretch(t, e);
211 *
this, t, e, stretch_ratio, channels, len, samples_to_read, samples_to_write,
214 for(std::size_t chan = 0; chan < channels; chan++)
218 t.start_discontinuous, t.end_discontinuous, ap.channel(chan), samples_offset,
222 ossia::snd::perform_upmix(this->upmix, channels, ap);
223 ossia::snd::perform_start_offset(this->start, ap);
225 m_prev_date = t.date;
233 [[nodiscard]] std::size_t channels()
const
235 return m_handle ? m_handle.channels() : 0;
237 [[nodiscard]] std::size_t duration()
const
239 return m_handle ? m_handle.totalPCMFrameCount() : 0;
243 libav_handle m_handle{};
245 ossia::audio_outlet audio_out;
250 ossia::pod_vector<float> m_tmp{};
251 boost::circular_buffer<float> m_channel_q;
constexpr OSSIA_INLINE auto max(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
max function tailored for values
Definition: math.hpp:96
The time_value class.
Definition: ossia/editor/scenario/time_value.hpp:28