commit 59883095b00ba55ce7441a22e8de6971059e0041
parent ac7ab7067e81f8ab3748de26acefc4c8f31ec8ea
Author: Louis Burda <quent.burda@gmail.com>
Date: Wed, 13 Mar 2024 20:34:43 +0100
Let minimp3 handle file mapping and extracting mp3 metadata
Diffstat:
M | mplay.mp3.c | | | 177 | ++++++++++++++++--------------------------------------------------------------- |
1 file changed, 35 insertions(+), 142 deletions(-)
diff --git a/mplay.mp3.c b/mplay.mp3.c
@@ -1,7 +1,7 @@
#include "mplay.h"
#define MINIMP3_IMPLEMENTATION
-#include "minimp3.h"
+#include "minimp3_ex.h"
#include <pulse/sample.h>
#include <pulse/introspect.h>
@@ -25,38 +25,20 @@
#include <stdio.h>
#include <stdlib.h>
-struct audiofile {
- uint8_t *data;
- size_t len;
-};
-
struct decoder {
- mp3dec_t dec;
- uint8_t *pos;
- ssize_t left;
-
- mp3d_sample_t *samples;
- size_t sample_cnt;
- size_t sample_cap;
- size_t sample_max;
-
+ mp3dec_ex_t dec;
size_t sample_next;
-
- bool seek;
+ size_t samples_max;
+ size_t samples_read;
int rate;
int channels;
+ bool seek;
bool init;
bool pause;
};
-static pa_sample_spec pa_spec = {
- .format = PA_SAMPLE_S16LE,
- .rate = 44100,
- .channels = 2
-};
-
static pa_buffer_attr pa_buf = {
.fragsize = UINT32_MAX,
.maxlength = UINT32_MAX,
@@ -74,8 +56,6 @@ static pa_stream *pa_strm;
static pa_sink_input_info pa_strm_sink;
static bool pa_strm_sink_update;
-static struct audiofile audiofile = { 0 };
-
static struct decoder decoder = { 0 };
static pthread_t input_worker_thread;
@@ -139,99 +119,18 @@ get_line(char *buf, int size)
if (istty) term_set_raw();
}
-static uint8_t *
-map_file(const char *path, size_t *len)
-{
- struct stat attr;
- uint8_t *buf;
- int fd;
-
- fd = open(path, O_RDONLY);
- if (fd < 0) die("open %s:", path);
-
- if (fstat(fd, &attr))
- die("fstat %s:", path);
-
- if ((attr.st_mode & S_IFMT) == S_IFDIR)
- die("not a file: %s", path);
-
- buf = mmap(NULL, (size_t) attr.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (!buf) die("mmap %s:", path);
-
- *len = (size_t) attr.st_size;
-
- close(fd);
-
- return buf;
-}
-
-static size_t
-decode_next_frame(mp3d_sample_t *samples, size_t *size)
-{
- static const size_t max_cnt = MINIMP3_MAX_SAMPLES_PER_FRAME;
- mp3dec_frame_info_t info;
- size_t cnt;
-
- if (size) *size = 0;
-
- if (decoder.sample_next < decoder.sample_cnt) {
- cnt = MIN(max_cnt, decoder.sample_cnt - decoder.sample_next);
- *size = cnt * sizeof(mp3d_sample_t);
- } else {
- if (decoder.sample_cnt + max_cnt > decoder.sample_cap) {
- decoder.sample_cap = MAX(decoder.sample_cap * 2,
- decoder.sample_cnt + max_cnt);
- decoder.samples = realloc(decoder.samples,
- decoder.sample_cap * sizeof(mp3d_sample_t));
- if (!decoder.samples) die("realloc:");
- }
-
- cnt = (size_t) mp3dec_decode_frame(&decoder.dec, decoder.pos,
- (int) decoder.left, &decoder.samples[decoder.sample_cnt], &info);
- cnt *= (size_t) info.channels;
- decoder.sample_cnt += cnt;
-
- if (size) *size = (size_t) info.frame_bytes;
-
- if (!info.frame_bytes)
- return 0;
-
- if (!decoder.init) {
- decoder.rate = info.hz;
- decoder.channels = info.channels;
- }
-
- decoder.pos += info.frame_bytes;
- decoder.left -= info.frame_bytes;
- }
-
- if (samples != NULL)
- memcpy(samples, &decoder.samples[decoder.sample_next],
- cnt * sizeof(mp3d_sample_t));
- decoder.sample_next += cnt;
-
- return cnt;
-}
-
static void
-decoder_init(void)
+decoder_init(const char *filepath)
{
- mp3d_sample_t samples[MINIMP3_MAX_SAMPLES_PER_FRAME];
- size_t size;
-
- mp3dec_init(&decoder.dec);
- decoder.pos = audiofile.data;
- decoder.left = (ssize_t) audiofile.len;
+ if (mp3dec_ex_open(&decoder.dec, filepath, MP3D_SEEK_TO_SAMPLE))
+ die("mp3dec_ex_open");
- decoder.sample_cnt = 0;
decoder.sample_next = 0;
- decoder.sample_cap = MINIMP3_MAX_SAMPLES_PER_FRAME;
- decoder.samples = malloc(decoder.sample_cap * sizeof(mp3d_sample_t));
- if (!decoder.samples) die("malloc:");
+ decoder.samples_max = 0;
+ decoder.samples_max = decoder.dec.samples / (size_t)decoder.dec.info.channels;
- /* decode channel specs */
- decode_next_frame(samples, &size);
- if (!size) die("invalid mp3");
+ decoder.channels = decoder.dec.info.channels;
+ decoder.rate = decoder.dec.info.hz;
decoder.seek = false;
decoder.pause = false;
@@ -241,15 +140,7 @@ decoder_init(void)
static void
decoder_seek(size_t sample_pos)
{
- size_t size, cnt;
-
- while (decoder.sample_next < sample_pos) {
- cnt = decode_next_frame(NULL, &size);
- if (!size) {
- mplay_status(MPLAY_INFO_EXIT, "from seek");
- exit(0);
- }
- }
+ mp3dec_ex_seek(&decoder.dec, sample_pos * (size_t)decoder.channels);
decoder.sample_next = sample_pos;
}
@@ -263,28 +154,31 @@ pa_stream_drain_callback(pa_stream *stream, int success, void *data)
static void
pa_stream_write_callback(pa_stream *stream, size_t requested, void *data)
{
- mp3d_sample_t samples[MINIMP3_MAX_SAMPLES_PER_FRAME];
+ mp3dec_frame_info_t info;
+ mp3d_sample_t *samples;
pa_operation *op;
ssize_t remaining;
- size_t cnt, size;
+ size_t cnt;
remaining = (ssize_t) requested;
while (remaining > 0) {
- cnt = decode_next_frame(samples, &size);
- if (!size) {
+ cnt = mp3dec_ex_read_frame(&decoder.dec, &samples, &info, requested);
+ if (!cnt) {
op = pa_stream_drain(pa_strm,
pa_stream_drain_callback, NULL);
pa_operation_unref(op);
return;
}
- if (!cnt) continue;
pa_stream_write(stream, samples,
cnt * sizeof(mp3d_sample_t), NULL, 0,
decoder.seek ? PA_SEEK_RELATIVE_ON_READ: PA_SEEK_RELATIVE);
decoder.seek = false;
- remaining -= (ssize_t) (cnt * sizeof(mp3d_sample_t));
+ decoder.sample_next += cnt / (size_t)decoder.channels;
+ decoder.samples_read = decoder.sample_next;
+ decoder.samples_max = MAX(decoder.samples_max, decoder.samples_read);
+ remaining -= (ssize_t) (cnt * (size_t)decoder.channels * sizeof(mp3d_sample_t));
}
}
@@ -347,7 +241,7 @@ stream_samples_buffered(void)
last_write_index = (size_t) MAX(0, info->write_index);
buffered = (last_write_index - last_read_index)
- / sizeof(mp3d_sample_t);
+ / ((size_t) decoder.channels * sizeof(mp3d_sample_t));
last_read_index = (size_t) MAX(0, info->read_index);
@@ -371,19 +265,19 @@ user_vol(void)
static double
user_pos(void)
{
- size_t sample_pos;
+ ssize_t sample_pos;
- sample_pos = (size_t) MAX(0,
- (ssize_t) decoder.sample_next - (ssize_t) stream_samples_buffered());
+ sample_pos = (ssize_t) decoder.samples_read;
+ sample_pos -= (ssize_t) stream_samples_buffered();
+ sample_pos = MAX(0, sample_pos);
- return (double) sample_pos * 1.F / (double) (decoder.rate * decoder.channels);
+ return (double) sample_pos * 1.F / (double) decoder.rate;
}
static double
user_end(void)
{
- return (double) decoder.sample_max * 1.F
- / (double) (decoder.rate * decoder.channels);
+ return (double) decoder.samples_max * 1.F / (double) decoder.rate;
}
static void
@@ -577,8 +471,13 @@ static void
pulse_stream_init(void)
{
pa_channel_map pa_chmap;
+ pa_sample_spec pa_spec;
int ret;
+ pa_spec.format = PA_SAMPLE_S16LE;
+ pa_spec.channels = (uint8_t) decoder.channels;
+ pa_spec.rate = (uint32_t) decoder.rate;
+
pa_channel_map_init_stereo(&pa_chmap);
pa_strm = pa_stream_new(pa_ctx, "mplay.mp3", &pa_spec, &pa_chmap);
@@ -622,8 +521,6 @@ cleanup(void)
pa_context_disconnect(pa_ctx);
pa_context_unref(pa_ctx);
- munmap(audiofile.data, audiofile.len);
-
if (input_worker_alive)
pthread_kill(input_worker_thread, SIGINT);
}
@@ -657,11 +554,7 @@ main(int argc, const char **argv)
istty = isatty(0);
- audiofile.data = map_file(file, &audiofile.len);
- decoder_init();
-
- pa_spec.channels = (uint8_t) decoder.channels;
- pa_spec.rate = (uint32_t) decoder.rate;
+ decoder_init(file);
pa_mloop = pa_threaded_mainloop_new();
if (!pa_mloop) die("pa_threaded_mainloop_new");