You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
58 lines
1.4 KiB
C++
58 lines
1.4 KiB
C++
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
// Copyright The Music Player Daemon Project
|
|
|
|
#include "Interleave.hxx"
|
|
#include "Buffer.hxx"
|
|
#include "Error.hxx"
|
|
#include "pcm/Interleave.hxx"
|
|
|
|
extern "C" {
|
|
#include <libavutil/frame.h>
|
|
}
|
|
|
|
#include <cassert>
|
|
#include <new> // for std::bad_alloc
|
|
|
|
namespace Ffmpeg {
|
|
|
|
std::span<const std::byte>
|
|
InterleaveFrame(const AVFrame &frame, FfmpegBuffer &buffer)
|
|
{
|
|
assert(frame.nb_samples > 0);
|
|
|
|
const auto format = AVSampleFormat(frame.format);
|
|
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 25, 100)
|
|
const unsigned channels = frame.ch_layout.nb_channels;
|
|
#else
|
|
const unsigned channels = frame.channels;
|
|
#endif
|
|
const std::size_t n_frames = frame.nb_samples;
|
|
|
|
int plane_size;
|
|
const int data_size =
|
|
av_samples_get_buffer_size(&plane_size, channels,
|
|
n_frames, format, 1);
|
|
assert(data_size != 0);
|
|
if (data_size < 0)
|
|
throw MakeFfmpegError(data_size);
|
|
|
|
std::byte *output_buffer;
|
|
if (av_sample_fmt_is_planar(format) && channels > 1) {
|
|
output_buffer = buffer.GetT<std::byte>(data_size);
|
|
if (output_buffer == nullptr)
|
|
/* Not enough memory - shouldn't happen */
|
|
throw std::bad_alloc();
|
|
|
|
PcmInterleave(output_buffer,
|
|
{(const void *const*)frame.extended_data, channels},
|
|
n_frames,
|
|
av_get_bytes_per_sample(format));
|
|
} else {
|
|
output_buffer = (std::byte *)frame.extended_data[0];
|
|
}
|
|
|
|
return { output_buffer, (size_t)data_size };
|
|
}
|
|
|
|
} // namespace Ffmpeg
|