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>
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>
25class 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 std::string label() const noexcept
override {
return "sound_libav"; }
48 void set_start(std::size_t v) { start = v; }
50 void set_upmix(std::size_t v) { upmix = v; }
52 void set_sound(libav_handle hdl)
56 m_handle = std::move(hdl);
59 m_channel_q = boost::circular_buffer<float>(8192 * m_handle.channels());
62 void transport(time_value flicks)
override
66 m_handle.format, m_handle.codec, m_handle.stream, flicks.impl, AVSEEK_FLAG_ANY);
69 void fetch_from_libav(
int samples_to_write)
71 const std::size_t channels = this->channels();
75 auto floats_to_write = channels * samples_to_write;
76 while(m_channel_q.size() < floats_to_write)
79 if(m_channel_q.capacity() < 4 * floats_to_write)
81 m_channel_q.set_capacity(4 * floats_to_write);
85 auto fmt_ctx = m_handle.format;
86 auto codec_ctx = m_handle.codec;
87 auto stream = m_handle.stream;
91 av_packet_unref(packet);
92 ret = av_read_frame(fmt_ctx, packet);
94 while(ret >= 0 && ret != AVERROR(EOF) && packet->stream_index != stream->index)
96 av_packet_unref(packet);
97 ret = av_read_frame(fmt_ctx, packet);
99 if(ret == AVERROR(EOF))
109 ret = avcodec_send_packet(codec_ctx, packet);
112 ret = avcodec_receive_frame(codec_ctx, frame);
115 const int samples = frame->nb_samples;
116 m_tmp.resize(samples * channels, boost::container::default_init);
117 float* out_ptr = m_tmp.data();
118 const int read_samples = swr_convert(
119 m_handle.resample, (uint8_t**)&out_ptr, samples,
120 (
const uint8_t**)frame->extended_data, samples);
123 m_channel_q.end(), out_ptr, out_ptr + read_samples * channels);
130 template <
typename T>
132 fetch_audio(int64_t start, int64_t samples_to_write, T** audio_array_base)
noexcept
134 const std::size_t channels = this->channels();
138 fetch_from_libav(samples_to_write);
141 for(
int k = 0; k < samples_to_write; k++)
143 for(std::size_t chan = 0; chan < channels; chan++)
145 if(m_channel_q.size() > 0)
147 audio_array_base[chan][k] = m_channel_q.front();
148 m_channel_q.pop_front();
152 audio_array_base[chan][k] = 0.;
158 void run(
const ossia::token_request& t, ossia::exec_state_facade e)
noexcept override
167 const auto channels = m_handle.channels();
168 const auto len = m_handle.totalPCMFrameCount();
170 ossia::audio_port& ap = *audio_out;
171 ap.set_channels(std::max((std::size_t)upmix, (std::size_t)channels));
173 const auto [samples_to_read, samples_to_write]
174 = snd::sample_info(e.bufferSize(), e.modelToSamples(), t);
175 if(samples_to_write <= 0)
178 assert(samples_to_write > 0);
180 const auto samples_offset = t.physical_start(e.modelToSamples());
183 if(t.prev_date < m_prev_date)
188 if(t.prev_date != 0_tv)
190 transport(t.prev_date);
200 transport(t.prev_date);
204 for(
int chan = 0; chan < channels; chan++)
206 ap.channel(chan).resize(e.bufferSize());
209 double stretch_ratio = update_stretch(t, e);
213 *
this, t, e, stretch_ratio, channels, len, samples_to_read, samples_to_write,
216 for(
int chan = 0; chan < channels; chan++)
220 t.start_discontinuous, t.end_discontinuous, ap.channel(chan), samples_offset,
224 ossia::snd::perform_upmix(this->upmix, channels, ap);
225 ossia::snd::perform_start_offset(this->start, ap);
227 m_prev_date = t.date;
235 [[nodiscard]] std::size_t channels()
const
237 return m_handle ? m_handle.channels() : 0;
239 [[nodiscard]] std::size_t duration()
const
241 return m_handle ? m_handle.totalPCMFrameCount() : 0;
245 libav_handle m_handle{};
247 ossia::audio_outlet audio_out;
252 ossia::pod_vector<float> m_tmp{};
253 boost::circular_buffer<float> m_channel_q;
The time_value class.
Definition ossia/editor/scenario/time_value.hpp:30