ffmpeg support on linux, and check compiled vs. runtime versions of ffmpeg

This commit is contained in:
2026-04-28 15:03:03 +02:00
parent 569ba05514
commit d81a4b7417
9 changed files with 289 additions and 35 deletions
+148 -11
View File
@@ -100,7 +100,7 @@ typedef struct _queue_ {
struct _queue_ *prev;
} Queue_t;
typedef int(*ao_play_func_t)(void *, char *, uint32_t);
struct AO_Handle;
typedef struct {
Queue_t *play_queue;
@@ -109,6 +109,7 @@ typedef struct {
int paused;
ao_device *ao_device;
int requested_bits_per_sample;
int dev_bits_per_sample;
int dev_endianess;
int dev_channels;
@@ -348,9 +349,131 @@ static void init_ao()
if (!init) {
ao_initialize();
atexit(at_exit_shutdown_ao);
init = 1;
}
}
static ao_device *try_open_device(int bits, int rate, int channels, int byte_format,
const char *wav_file_output,
int *opened_bits)
{
int candidates[3];
int n = 0;
candidates[n++] = bits;
if (bits > 24) candidates[n++] = 24;
if (bits > 16) candidates[n++] = 16;
for (int i = 0; i < n; i++) {
ao_sample_format fmt;
fmt.bits = candidates[i];
fmt.rate = rate;
fmt.byte_format = byte_format;
fmt.channels = channels;
fmt.matrix = NULL;
ao_device *dev;
if (wav_file_output != NULL) {
int driver_id = ao_driver_id("wav");
dev = ao_open_file(driver_id, wav_file_output, 1, &fmt, NULL);
} else {
dev = ao_open_live(ao_default_driver_id(), &fmt, NULL);
}
if (dev != NULL) {
*opened_bits = candidates[i];
return dev;
}
}
return NULL;
}
static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits)
{
if (req_bits > out_bits) {
sample >>= (req_bits - out_bits);
} else if (req_bits < out_bits) {
sample <<= (out_bits - req_bits);
}
return sample;
}
static inline int32_t read_sample(unsigned char *mem, int req_bytes, int little_endian)
{
uint32_t v = 0;
for (int i = 0; i < req_bytes; i++) {
int idx = little_endian ? i : (req_bytes - i - 1);
v |= ((uint32_t) mem[idx]) << (8 * i);
}
if (req_bytes < 4) {
int bits = req_bytes * 8;
uint32_t sign = 1u << (bits - 1);
v = (v ^ sign) - sign;
}
return (int32_t) v;
}
static inline void store_sample(unsigned char *dst, int32_t sample, int out_bytes, int is_little_endian)
{
for (int i = 0; i < out_bytes; i++) {
int idx = is_little_endian ? i : (out_bytes - i - 1);
dst[idx] = sample & 0xff;
sample >>= 8;
}
}
static void *convert_req_to_real(AO_Handle *h, void *mem, int mem_size, BufferInfo_t *info, int *out_size)
{
int endianess = h->dev_endianess;
int little_endian = (endianess == AO_FMT_LITTLE);
if (!little_endian && endianess == AO_FMT_NATIVE) little_endian = littleEndian();
int requested_bits = h->requested_bits_per_sample;
int output_bits = h->dev_bits_per_sample;
int req_bytes = (requested_bits / 8);
int out_bytes = (output_bits / 8);
int samples = (mem_size / req_bytes);
unsigned char *buf_out = (unsigned char *) malloc(samples * out_bytes);
if (buf_out == NULL) {
fprintf(stderr, "Allocation of output buffer of %d samples of %d bits gives NULL", samples, output_bits);
*out_size = 0;
return NULL;
}
if (requested_bits == output_bits) {
*out_size = mem_size;
memcpy(buf_out, mem, mem_size);
} else {
// convert samples.
int sample;
unsigned char *p_in = (unsigned char *) mem;
unsigned char *p_out = buf_out;
for(sample = 0; sample < samples; sample++, p_in += req_bytes, p_out += out_bytes) {
register int32_t smpl;
smpl = read_sample(p_in, req_bytes, little_endian);
int32_t out_smpl = convert_bits(smpl, requested_bits, output_bits);
store_sample(p_out, out_smpl, out_bytes, little_endian);
}
*out_size = samples * out_bytes;
}
return buf_out;
}
void *ao_create_async(int bits, int rate, int channels, int byte_format, const char *wav_file_output)
{
init_ao();
@@ -364,21 +487,18 @@ void *ao_create_async(int bits, int rate, int channels, int byte_format, const c
fmt.channels = channels;
fmt.matrix = NULL;
ao_device *dev;
if (wav_file_output != NULL) {
int driver_id = ao_driver_id("wav");
dev = ao_open_file(driver_id, wav_file_output, 1, &fmt, NULL);
} else {
dev = ao_open_live(ao_default_driver_id(), &fmt, NULL);
}
int opened_bits = 0;
ao_device *dev = try_open_device(bits, rate, channels, byte_format, wav_file_output, &opened_bits);
if (dev == NULL) {
fprintf(stderr, "Cannot open ao-device, error code = %d\n", errno);
free(handle);
return NULL;
}
handle->ao_device = dev;
handle->dev_bits_per_sample = bits;
handle->requested_bits_per_sample = bits;
handle->dev_bits_per_sample = opened_bits;
handle->dev_channels = channels;
handle->dev_rate = rate;
handle->dev_endianess = byte_format;
@@ -563,12 +683,23 @@ void ao_play_async(void *ao_handle, int music_id, double at_second, double music
case flac: {
int store_size = 0;
void *store_mem = convertFlac(mem, buf_size, &info, &store_size);
q = new_elem(PLAY, music_id, at_second, music_duration, store_size, store_mem);
int ao_size = 0;
void *ao_mem = convert_req_to_real(ao_handle, store_mem, store_size, &info, &ao_size);
q = new_elem(PLAY, music_id, at_second, music_duration, ao_size, ao_mem);
free(store_mem);
free(ao_mem);
}
break;
case ao: {
q = new_elem(PLAY, music_id, at_second, music_duration, buf_size, mem);
int ao_size = 0;
void *ao_mem = convert_req_to_real(ao_handle, mem, buf_size, &info, &ao_size);
q = new_elem(PLAY, music_id, at_second, music_duration, ao_size, ao_mem);
free(ao_mem);
}
break;
case mpg123: {
@@ -680,3 +811,9 @@ void ao_pause_async(void *ao_handle, int paused)
int ao_real_output_bits_async(void *handle)
{
AO_Handle *h = (AO_Handle *) handle;
return h->dev_bits_per_sample;
}
+1
View File
@@ -44,5 +44,6 @@ AOPLAYASYNC_EXPORT void ao_set_volume_async(void *ao_handle, double percentage);
AOPLAYASYNC_EXPORT double ao_volume_async(void *ao_handle);
AOPLAYASYNC_EXPORT int ao_bufsize_async(void *handle);
AOPLAYASYNC_EXPORT int ao_real_output_bits_async(void *handle);
#endif // AO_PLAYASYNC_H