mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Wrap some ffmpeg code to do raw audio rate conversion
This commit is contained in:
parent
e1a864aef4
commit
a69f0b221f
@ -143,6 +143,9 @@ hunspell_lib_dirs = []
|
|||||||
hyphen_inc_dirs = []
|
hyphen_inc_dirs = []
|
||||||
hyphen_lib_dirs = []
|
hyphen_lib_dirs = []
|
||||||
|
|
||||||
|
ffmpeg_inc_dirs = []
|
||||||
|
ffmpeg_lib_dirs = []
|
||||||
|
|
||||||
uchardet_inc_dirs, uchardet_lib_dirs, uchardet_libs = [], [], ['uchardet']
|
uchardet_inc_dirs, uchardet_lib_dirs, uchardet_libs = [], [], ['uchardet']
|
||||||
|
|
||||||
openssl_inc_dirs, openssl_lib_dirs = [], []
|
openssl_inc_dirs, openssl_lib_dirs = [], []
|
||||||
@ -206,6 +209,10 @@ else:
|
|||||||
uchardet_lib_dirs = pkgconfig_lib_dirs('uchardet', '', '/usr/lib')
|
uchardet_lib_dirs = pkgconfig_lib_dirs('uchardet', '', '/usr/lib')
|
||||||
uchardet_libs = pkgconfig_libs('uchardet', '', '')
|
uchardet_libs = pkgconfig_libs('uchardet', '', '')
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(sw, 'ffmpeg')):
|
||||||
|
ffmpeg_inc_dirs = [os.path.join(sw, 'ffmpeg', 'include')] + ffmpeg_inc_dirs
|
||||||
|
ffmpeg_lib_dirs = [os.path.join(sw, 'ffmpeg', 'lib')] + ffmpeg_lib_dirs
|
||||||
|
|
||||||
|
|
||||||
if 'PODOFO_PREFIX' in os.environ:
|
if 'PODOFO_PREFIX' in os.environ:
|
||||||
os.environ['PODOFO_LIB_DIR'] = os.path.join(os.environ['PODOFO_PREFIX'], 'lib')
|
os.environ['PODOFO_LIB_DIR'] = os.path.join(os.environ['PODOFO_PREFIX'], 'lib')
|
||||||
|
@ -16,6 +16,14 @@
|
|||||||
"lib_dirs": "!hyphen_lib_dirs",
|
"lib_dirs": "!hyphen_lib_dirs",
|
||||||
"needs_c": "99"
|
"needs_c": "99"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ffmpeg",
|
||||||
|
"sources": "calibre/utils/ffmpeg.c",
|
||||||
|
"libraries": "avcodec avutil swresample",
|
||||||
|
"inc_dirs": "!ffmpeg_inc_dirs",
|
||||||
|
"lib_dirs": "!ffmpeg_lib_dirs",
|
||||||
|
"needs_c": "99"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "uchardet",
|
"name": "uchardet",
|
||||||
"sources": "calibre/ebooks/uchardet.c",
|
"sources": "calibre/ebooks/uchardet.c",
|
||||||
|
88
src/calibre/utils/ffmpeg.c
Normal file
88
src/calibre/utils/ffmpeg.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* ffmpeg.c
|
||||||
|
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define UNICODE
|
||||||
|
#define PY_SSIZE_T_CLEAN
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include <libavutil/audio_fifo.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavutil/samplefmt.h>
|
||||||
|
#include <libavutil/common.h>
|
||||||
|
#include <libavutil/channel_layout.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libavutil/mem.h>
|
||||||
|
#include <libavutil/fifo.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
averror_as_python(int errnum) {
|
||||||
|
char buf[4096];
|
||||||
|
av_strerror(errnum, buf, sizeof(buf));
|
||||||
|
PyErr_SetString(PyExc_Exception, buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
resample_raw_audio_16bit(PyObject *self, PyObject *args) {
|
||||||
|
int input_sample_rate, output_sample_rate, input_num_channels = 1, output_num_channels = 1;
|
||||||
|
Py_buffer inb = {0};
|
||||||
|
if (!PyArg_ParseTuple(args, "y*ii|ii", &inb, &input_sample_rate, &output_sample_rate, &input_num_channels, &output_num_channels)) return NULL;
|
||||||
|
int64_t output_size = av_rescale_rnd(inb.len, output_sample_rate, input_sample_rate, AV_ROUND_UP);
|
||||||
|
uint8_t *output = av_malloc(output_size); // we have to use av_malloc as it aligns to vector boundaries
|
||||||
|
if (!output) { PyBuffer_Release(&inb); return PyErr_NoMemory(); }
|
||||||
|
AVChannelLayout input_layout = {0}, output_layout = {0};
|
||||||
|
av_channel_layout_default(&input_layout, input_num_channels);
|
||||||
|
av_channel_layout_default(&output_layout, output_num_channels);
|
||||||
|
SwrContext *swr_ctx = NULL;
|
||||||
|
static const enum AVSampleFormat fmt = AV_SAMPLE_FMT_S16;
|
||||||
|
const int bytes_per_sample = av_get_bytes_per_sample(fmt);
|
||||||
|
int ret = swr_alloc_set_opts2(&swr_ctx,
|
||||||
|
&output_layout, fmt, output_sample_rate,
|
||||||
|
&input_layout, fmt, input_sample_rate,
|
||||||
|
0, NULL);
|
||||||
|
if (ret != 0) { av_free(output); PyBuffer_Release(&inb); return averror_as_python(ret); }
|
||||||
|
#define free_resources av_free(output); PyBuffer_Release(&inb); swr_free(&swr_ctx);
|
||||||
|
if ((ret = swr_init(swr_ctx)) < 0) { free_resources; return averror_as_python(ret); }
|
||||||
|
const uint8_t *input = inb.buf;
|
||||||
|
ret = swr_convert(swr_ctx,
|
||||||
|
&output, output_size / (output_num_channels * bytes_per_sample),
|
||||||
|
&input, inb.len / (input_num_channels * bytes_per_sample)
|
||||||
|
);
|
||||||
|
if (ret < 0) { free_resources; return averror_as_python(ret); }
|
||||||
|
output_size = ret * output_num_channels * bytes_per_sample;
|
||||||
|
PyObject *ans = PyBytes_FromStringAndSize((char*)output, output_size);
|
||||||
|
free_resources;
|
||||||
|
#undef free_resources
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Boilerplate {{{
|
||||||
|
static int
|
||||||
|
exec_module(PyObject *module) { return 0; }
|
||||||
|
|
||||||
|
CALIBRE_MODINIT_FUNC PyInit_ffmpeg(void) {
|
||||||
|
static PyModuleDef_Slot slots[] = { {Py_mod_exec, exec_module}, {0, NULL} };
|
||||||
|
static PyMethodDef methods[] = {
|
||||||
|
{"resample_raw_audio_16bit", (PyCFunction)resample_raw_audio_16bit, METH_VARARGS,
|
||||||
|
"resample_raw_audio(input_data, input_sample_rate, output_sample_rate, input_num_channels=1, output_num_channels=1) -> Return resampled raw audio data."
|
||||||
|
},
|
||||||
|
{0} /* Sentinel */
|
||||||
|
};
|
||||||
|
static struct PyModuleDef module_def = {
|
||||||
|
.m_base = PyModuleDef_HEAD_INIT,
|
||||||
|
.m_name = "ffmpeg",
|
||||||
|
.m_doc = "Wrapper for the ffmpeg C libraries",
|
||||||
|
.m_methods = methods,
|
||||||
|
.m_slots = slots,
|
||||||
|
};
|
||||||
|
return PyModuleDef_Init(&module_def);
|
||||||
|
}
|
||||||
|
// }}}
|
Loading…
x
Reference in New Issue
Block a user