summaryrefslogtreecommitdiff
path: root/src/lib/ffmpeg/Interleave.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/ffmpeg/Interleave.cxx')
-rw-r--r--src/lib/ffmpeg/Interleave.cxx71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/lib/ffmpeg/Interleave.cxx b/src/lib/ffmpeg/Interleave.cxx
new file mode 100644
index 000000000..93a9a8bef
--- /dev/null
+++ b/src/lib/ffmpeg/Interleave.cxx
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2003-2020 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "Interleave.hxx"
+#include "Buffer.hxx"
+#include "Error.hxx"
+#include "pcm/Interleave.hxx"
+#include "util/ConstBuffer.hxx"
+
+extern "C" {
+#include <libavutil/frame.h>
+}
+
+#include <cassert>
+#include <new> // for std::bad_alloc
+
+namespace Ffmpeg {
+
+ConstBuffer<void>
+InterleaveFrame(const AVFrame &frame, FfmpegBuffer &buffer)
+{
+ assert(frame.nb_samples > 0);
+
+ const AVSampleFormat format = AVSampleFormat(frame.format);
+ const unsigned channels = frame.channels;
+ 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);
+
+ void *output_buffer;
+ if (av_sample_fmt_is_planar(format) && channels > 1) {
+ output_buffer = buffer.GetT<uint8_t>(data_size);
+ if (output_buffer == nullptr)
+ /* Not enough memory - shouldn't happen */
+ throw std::bad_alloc();
+
+ PcmInterleave(output_buffer,
+ ConstBuffer<const void *>((const void *const*)frame.extended_data,
+ channels),
+ n_frames,
+ av_get_bytes_per_sample(format));
+ } else {
+ output_buffer = frame.extended_data[0];
+ }
+
+ return { output_buffer, (size_t)data_size };
+}
+
+} // namespace Ffmpeg