diff options
| author | 2025-04-16 15:12:41 -0400 | |
|---|---|---|
| committer | 2025-04-16 15:15:01 -0400 | |
| commit | ae8822ec0327c4d5674f1dc79de926b230f27f1f (patch) | |
| tree | e57027812d73baf7ab617222aa55ad2fe4c33a55 /src/liana | |
| parent | 832b3ab11fd6457c59aed9d5bf12ba40c117f15d (diff) | |
| download | camu-ae8822ec0327c4d5674f1dc79de926b230f27f1f.tar.gz camu-ae8822ec0327c4d5674f1dc79de926b230f27f1f.tar.bz2 camu-ae8822ec0327c4d5674f1dc79de926b230f27f1f.zip | |
Highly wip waveform view
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/liana')
| -rw-r--r-- | src/liana/handlers/codec_server.c | 4 | ||||
| -rw-r--r-- | src/liana/list.c | 8 | ||||
| -rw-r--r-- | src/liana/meson.build | 3 | ||||
| -rw-r--r-- | src/liana/process.c | 115 | ||||
| -rw-r--r-- | src/liana/process.h | 13 | ||||
| -rw-r--r-- | src/liana/server.c | 13 | ||||
| -rw-r--r-- | src/liana/server.h | 3 |
7 files changed, 150 insertions, 9 deletions
diff --git a/src/liana/handlers/codec_server.c b/src/liana/handlers/codec_server.c index 7868a42..99db398 100644 --- a/src/liana/handlers/codec_server.c +++ b/src/liana/handlers/codec_server.c @@ -59,7 +59,9 @@ static void codec_server_write_info(struct lia_server_handler *handler, struct n nn_packet_write_u8(packet, stream->mode); nn_packet_write_u8(packet, stream->type); nn_packet_write_u64(packet, stream->duration); - nn_packet_write_s32(packet, i); + // stream->index = i is currently expected but not necessary. + al_assert(stream->index == (s32)i); + nn_packet_write_s32(packet, stream->index); switch (stream->mode) { case CAMU_NORMAL: { struct camu_video_format *fmt = &stream->video.fmt; diff --git a/src/liana/list.c b/src/liana/list.c index 1c7c6c9..0ceb591 100644 --- a/src/liana/list.c +++ b/src/liana/list.c @@ -148,7 +148,8 @@ static void pump_queue(struct lia_list *list); static bool handle_add_sink(struct lia_list *list, struct lia_list_sink *sink) { - if (list->current >= 0 && !list->idle) { + // The list being idle is not equivalent to current being unset. + if (list->current >= 0) { struct lia_list_entry *current = al_array_at(list->entries, list->current); u64 now = nn_get_timestamp(); u8 pause; @@ -243,9 +244,7 @@ static s32 get_sequence_from_entry_id(struct lia_list *list, u32 id) // Not returning the entry pointer here is a meaningful simplification. struct lia_list_entry *entry; al_array_foreach(list->entries, i, entry) { - if (entry->id == id) { - return (s32)i; - } + if (entry->id == id) return i; } return -1; } @@ -254,6 +253,7 @@ static bool handle_skipto(struct lia_list *list, s32 sequence, s32 index) { if (sequence == LIANA_SEQUENCE_ANY) sequence = list->current; if (sequence < 0) return true; // list->current = -1 + if (sequence == index) return true; if (sequence != list->current) { log_warn("Discarding out of date skip()."); return true; diff --git a/src/liana/meson.build b/src/liana/meson.build index 34abc66..12345c9 100644 --- a/src/liana/meson.build +++ b/src/liana/meson.build @@ -2,7 +2,8 @@ liana_server_src = [ 'list.c', 'server.c', 'handlers/codec_server.c', - 'handlers.c' + 'handlers.c', + 'process.c' ] liana_client_src = [ 'client.c', diff --git a/src/liana/process.c b/src/liana/process.c new file mode 100644 index 0000000..9a70210 --- /dev/null +++ b/src/liana/process.c @@ -0,0 +1,115 @@ +#ifdef CAMU_HAVE_FFMPEG +#include "../codec/ffmpeg/demuxer.h" +#include "../codec/ffmpeg/decoder.h" +#include "../codec/ffmpeg/resampler.h" +#endif + +#include "process.h" + +struct raw_samples_data { + struct camu_resampler *resampler; + u32 channels; + u32 bps; + struct nn_buffer buf; + u32 index; +}; + +static u32 append_samples(struct raw_samples_data *raw, u8 *data, u32 sample_count) +{ + u32 bytes = sample_count * raw->channels * raw->bps; + nn_buffer_write(&raw->buf, data, raw->index, bytes); + return bytes; +} + +static void data_callback(void *userdata, struct camu_codec_frame *frame) +{ + struct raw_samples_data *raw = (struct raw_samples_data *)userdata; + u8 **data = frame->av.frame->data; + s32 sample_count = frame->av.frame->nb_samples; + sample_count = raw->resampler->convert(raw->resampler, (const u8 **)data, sample_count); + data = raw->resampler->get_data(raw->resampler); + raw->index += append_samples(raw, data[0], (u32)sample_count); +} + +static void flush_resampler(struct camu_resampler *resampler, struct raw_samples_data *raw) +{ + s32 sample_count = resampler->flush(resampler); + u8 **data = resampler->get_data(resampler); + raw->index += append_samples(raw, data[0], (u32)sample_count); +} + +bool lia_prepare_visual_data(struct cch_handle *handle, struct lia_visual_data *data) +{ + struct camu_demuxer *demux = camu_ff_demuxer_create(); + struct camu_decoder *dec = camu_ff_decoder_create(); + struct camu_resampler *resampler = camu_ff_resampler_create(); + data->samples = NULL; + + if (!demux->init(demux, handle)) { + goto out; + } + + struct camu_codec_stream *stream; + struct camu_codec_stream *selected = NULL; + al_array_foreach_ptr(demux->streams, i, stream) { + if (stream->type == CAMU_STREAM_AUDIO) { + selected = stream; + break; + } + } + if (!selected) goto out; + demux->subscribed = 1 << selected->index; + + struct camu_resampler_format fmt; + AVCodecParameters *codecpar = selected->av.stream->codecpar; + fmt.in.format = codecpar->format; + fmt.req.format = CAMU_SAMPLE_FORMAT_S16; + fmt.in.sample_rate = codecpar->sample_rate; + fmt.req.sample_rate = codecpar->sample_rate; + av_channel_layout_copy(&fmt.in.channel_layout, &codecpar->ch_layout); + av_channel_layout_copy(&fmt.req.channel_layout, &codecpar->ch_layout); + fmt.in.channel_count = codecpar->ch_layout.nb_channels; + fmt.req.channel_count = codecpar->ch_layout.nb_channels; + + struct raw_samples_data raw; + raw.resampler = resampler; + raw.channels = fmt.req.channel_count; + raw.bps = camu_audio_format_bytes_per_sample(&fmt.req); + nn_buffer_init(&raw.buf); + raw.index = 0; + + if (!dec->init(dec, NULL, selected, data_callback, &raw)) { + goto out; + } + + fmt.resampler_needed = true; + if (!resampler->init(resampler, &fmt)) { + goto out; + } + + AVPacket *pkt = av_packet_alloc(); + struct camu_codec_packet packet = { .av.pkt = pkt }; + s32 status; + do { + status = demux->get_packet(demux, &packet); + if (status == CAMU_OK) { + dec->push_av_packet(dec, pkt); + dec->process(dec); + av_packet_unref(pkt); + } + } while (status == CAMU_OK); + dec->flush(dec); + flush_resampler(resampler, &raw); + + data->size = raw.index; + data->samples = raw.buf.data; + data->count = raw.index / raw.channels / raw.bps; + camu_audio_format_copy(&data->fmt, &fmt.req); + +out: + demux->free(&demux); + dec->free(&dec); + resampler->free(&resampler); + + return data->samples != NULL; +} diff --git a/src/liana/process.h b/src/liana/process.h new file mode 100644 index 0000000..a71728b --- /dev/null +++ b/src/liana/process.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../codec/codec.h" +#include "../cache/handle.h" + +struct lia_visual_data { + struct camu_audio_format fmt; + u32 size; + u8 *samples; + u32 count; +}; + +bool lia_prepare_visual_data(struct cch_handle *handle, struct lia_visual_data *data); diff --git a/src/liana/server.c b/src/liana/server.c index abf4154..9d1f42a 100644 --- a/src/liana/server.c +++ b/src/liana/server.c @@ -1,6 +1,7 @@ #include "server.h" #include "handler.h" #include "handlers.h" +#include "process.h" #include "list.h" static inline u32 get_incremental_id(struct lia_server *server) @@ -445,16 +446,24 @@ static void duration_signal_callback(void *userdata) nn_signal_stop(&node->signal); nn_thread_join(&node->thread); node->handler->free(&node->handler); + bool got_visual_data = false; + struct lia_visual_data visual_data; + //cch_handle_seek(&node->handle, 0, SEEK_SET); + //got_visual_data = lia_prepare_visual_data(&node->handle, &visual_data); cch_entry_return_handle(node->entry, &node->handle); if (should_free_node(node)) { free_node(node); } else { if (node->errored) { - node->callback(node->userdata, LIANA_NODE_ERRORED, LIANA_TIMESTAMP_INVALID); + al_assert(node->duration == LIANA_TIMESTAMP_INVALID); + node->callback(node->userdata, LIANA_NODE_ERRORED, &node->duration); } else { - node->callback(node->userdata, LIANA_NODE_DURATION, node->duration); + node->callback(node->userdata, LIANA_NODE_DURATION, &node->duration); } } + if (got_visual_data) { + node->callback(node->userdata, LIANA_NODE_VISUAL_DATA, &visual_data); + } } void lia_node_get_duration(struct lia_node *node) diff --git a/src/liana/server.h b/src/liana/server.h index 679d607..13f4a6e 100644 --- a/src/liana/server.h +++ b/src/liana/server.h @@ -41,6 +41,7 @@ struct lia_node_connection { enum { LIANA_NODE_DURATION = 0, + LIANA_NODE_VISUAL_DATA, LIANA_NODE_ERRORED }; @@ -52,7 +53,7 @@ struct lia_node { bool closed; u64 duration; struct lia_server *server; - void (*callback)(void *, u8, u64); + void (*callback)(void *, u8, void *); void *userdata; // Temporary copy-paste from node_connection. bool errored; |