1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // mapper-multiple.c - a muxer/demuxer for multiple containers.
4 //
5 // Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6 //
7 // Licensed under the terms of the GNU General Public License, version 2.
8
9 #include "mapper.h"
10 #include "misc.h"
11
12 struct multiple_state {
13 void (*align_frames)(void *frame_buf, unsigned int frame_count,
14 char **buf, unsigned int bytes_per_sample,
15 struct container_context *cntrs,
16 unsigned int cntr_count);
17 char **bufs;
18 unsigned int cntr_count;
19 };
20
align_to_i(void * frame_buf,unsigned int frame_count,char ** src_bufs,unsigned int bytes_per_sample,struct container_context * cntrs,unsigned int cntr_count)21 static void align_to_i(void *frame_buf, unsigned int frame_count,
22 char **src_bufs, unsigned int bytes_per_sample,
23 struct container_context *cntrs, unsigned int cntr_count)
24 {
25 char *dst = frame_buf;
26 char *src;
27 unsigned int dst_pos;
28 unsigned int src_pos;
29 struct container_context *cntr;
30 int i, j;
31
32 // src: first channel in each of interleaved buffers in containers =>
33 // dst:interleaved.
34 for (i = 0; i < cntr_count; ++i) {
35 src = src_bufs[i];
36 cntr = cntrs + i;
37
38 for (j = 0; j < frame_count; ++j) {
39 // Use first src channel for each of dst channel.
40 src_pos = bytes_per_sample * cntr->samples_per_frame * j;
41 dst_pos = bytes_per_sample * (cntr_count * j + i);
42
43 memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
44 }
45 }
46 }
47
align_from_i(void * frame_buf,unsigned int frame_count,char ** dst_bufs,unsigned int bytes_per_sample,struct container_context * cntrs,unsigned int cntr_count)48 static void align_from_i(void *frame_buf, unsigned int frame_count,
49 char **dst_bufs, unsigned int bytes_per_sample,
50 struct container_context *cntrs,
51 unsigned int cntr_count)
52 {
53 char *src = frame_buf;
54 char *dst;
55 unsigned int src_pos;
56 unsigned int dst_pos;
57 struct container_context *cntr;
58 int i, j;
59
60 for (i = 0; i < cntr_count; ++i) {
61 dst = dst_bufs[i];
62 cntr = cntrs + i;
63
64 for (j = 0; j < frame_count; ++j) {
65 // Use first src channel for each of dst channel.
66 src_pos = bytes_per_sample * (cntr_count * j + i);
67 dst_pos = bytes_per_sample * cntr->samples_per_frame * j;
68
69 memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
70 }
71 }
72 }
73
multiple_pre_process(struct mapper_context * mapper,struct container_context * cntrs,unsigned int cntr_count)74 static int multiple_pre_process(struct mapper_context *mapper,
75 struct container_context *cntrs,
76 unsigned int cntr_count)
77 {
78 struct multiple_state *state = mapper->private_data;
79 struct container_context *cntr;
80 int i;
81
82 // Additionally, format of samples in the containers should be the same
83 // as the format in PCM substream.
84 for (i = 0; i < cntr_count; ++i) {
85 cntr = cntrs + i;
86 if (mapper->bytes_per_sample != cntr->bytes_per_sample)
87 return -EINVAL;
88 }
89 state->cntr_count = cntr_count;
90
91 // Decide method to align frames.
92 if (mapper->type == MAPPER_TYPE_DEMUXER) {
93 if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
94 mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
95 state->align_frames = align_from_i;
96 else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
97 mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
98 state->align_frames = NULL;
99 else
100 return -EINVAL;
101 } else {
102 if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
103 mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
104 state->align_frames = align_to_i;
105 else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
106 mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
107 state->align_frames = NULL;
108 else
109 return -EINVAL;
110 }
111
112 if (state->align_frames) {
113 // Furthermore, in demuxer case, each container should be
114 // configured to store one sample per frame.
115 if (mapper->type == MAPPER_TYPE_DEMUXER) {
116 for (i = 0; i < cntr_count; ++i) {
117 cntr = cntrs + i;
118 if (cntr->samples_per_frame != 1)
119 return -EINVAL;
120 }
121 }
122
123 state->bufs = calloc(cntr_count, sizeof(char *));
124 if (state->bufs == NULL)
125 return -ENOMEM;
126
127 for (i = 0; i < cntr_count; ++i) {
128 unsigned int bytes_per_buffer;
129
130 // Allocate intermediate buffer as the same size as a
131 // period for each of containers.
132 cntr = cntrs + i;
133
134 bytes_per_buffer = mapper->bytes_per_sample *
135 cntr->samples_per_frame *
136 mapper->frames_per_buffer;
137
138 state->bufs[i] = malloc(bytes_per_buffer);
139 if (state->bufs[i] == NULL)
140 return -ENOMEM;
141 memset(state->bufs[i], 0, bytes_per_buffer);
142 }
143 }
144
145 return 0;
146 }
147
process_containers(char ** src_bufs,unsigned int * frame_count,struct container_context * cntrs,unsigned int cntr_count)148 static int process_containers(char **src_bufs, unsigned int *frame_count,
149 struct container_context *cntrs,
150 unsigned int cntr_count)
151 {
152 struct container_context *cntr;
153 char *src;
154 int i;
155 int err = 0;
156
157 // TODO: arrangement for *frame_count.
158 for (i = 0; i < cntr_count; ++i) {
159 cntr = &cntrs[i];
160 src = src_bufs[i];
161
162 err = container_context_process_frames(cntr, src, frame_count);
163 if (err < 0)
164 break;
165 }
166
167 return err;
168 }
169
multiple_muxer_process_frames(struct mapper_context * mapper,void * frame_buf,unsigned int * frame_count,struct container_context * cntrs,unsigned int cntr_count)170 static int multiple_muxer_process_frames(struct mapper_context *mapper,
171 void *frame_buf,
172 unsigned int *frame_count,
173 struct container_context *cntrs,
174 unsigned int cntr_count)
175 {
176 struct multiple_state *state = mapper->private_data;
177 char **src_bufs;
178 int err;
179
180 // If need to align PCM frames, process PCM frames to the intermediate
181 // buffer once.
182 if (!state->align_frames) {
183 // The most likely.
184 src_bufs = frame_buf;
185 } else {
186 src_bufs = state->bufs;
187 }
188 err = process_containers(src_bufs, frame_count, cntrs, cntr_count);
189 if (err < 0)
190 return err;
191
192 // Unlikely.
193 if (src_bufs != frame_buf && *frame_count > 0) {
194 state->align_frames(frame_buf, *frame_count, src_bufs,
195 mapper->bytes_per_sample, cntrs,
196 cntr_count);
197 }
198
199 return 0;
200 }
201
multiple_demuxer_process_frames(struct mapper_context * mapper,void * frame_buf,unsigned int * frame_count,struct container_context * cntrs,unsigned int cntr_count)202 static int multiple_demuxer_process_frames(struct mapper_context *mapper,
203 void *frame_buf,
204 unsigned int *frame_count,
205 struct container_context *cntrs,
206 unsigned int cntr_count)
207 {
208 struct multiple_state *state = mapper->private_data;
209 char **dst_bufs;
210
211 // If need to align PCM frames, process PCM frames to the intermediate
212 // buffer once.
213 if (!state->align_frames) {
214 // The most likely.
215 dst_bufs = frame_buf;
216 } else {
217 dst_bufs = state->bufs;
218 state->align_frames(frame_buf, *frame_count, dst_bufs,
219 mapper->bytes_per_sample, cntrs,
220 cntr_count);
221 }
222
223 return process_containers(dst_bufs, frame_count, cntrs, cntr_count);
224 }
225
multiple_post_process(struct mapper_context * mapper)226 static void multiple_post_process(struct mapper_context *mapper)
227 {
228 struct multiple_state *state = mapper->private_data;
229 int i;
230
231 if (state->bufs) {
232 for (i = 0; i < state->cntr_count; ++i) {
233 if (state->bufs[i])
234 free(state->bufs[i]);
235 }
236 free(state->bufs);
237 }
238
239 state->bufs = NULL;
240 state->align_frames = NULL;
241 }
242
243 const struct mapper_data mapper_muxer_multiple = {
244 .ops = {
245 .pre_process = multiple_pre_process,
246 .process_frames = multiple_muxer_process_frames,
247 .post_process = multiple_post_process,
248 },
249 .private_size = sizeof(struct multiple_state),
250 };
251
252 const struct mapper_data mapper_demuxer_multiple = {
253 .ops = {
254 .pre_process = multiple_pre_process,
255 .process_frames = multiple_demuxer_process_frames,
256 .post_process = multiple_post_process,
257 },
258 .private_size = sizeof(struct multiple_state),
259 };
260