1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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;
};
#ifdef CAMU_HAVE_FFMPEG
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 = NULL;
al_array_foreach_ptr(demux->streams, i, stream) {
if (stream->type == CAMU_STREAM_AUDIO) {
demux->subscribed = 1 << stream->index;
break;
}
}
if (!stream || demux->subscribed == 0) goto out;
struct camu_resampler_format fmt;
AVCodecParameters *codecpar = stream->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;
camu_copy_channel_layout(&fmt.in.channel_layout, &AV_CODECPAR_CHANNEL_LAYOUT(codecpar));
camu_copy_channel_layout(&fmt.req.channel_layout, &AV_CODECPAR_CHANNEL_LAYOUT(codecpar));
fmt.in.channel_count = AV_CODECPAR_CHANNELS(codecpar);
fmt.req.channel_count = AV_CODECPAR_CHANNELS(codecpar);
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, stream, 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;
}
#endif
|