1 // SPDX-License-Identifier: GPL-2.0
3 // mapper-multiple.c - a muxer/demuxer for multiple containers.
5 // Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
7 // Licensed under the terms of the GNU General Public License, version 2.
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);
18 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)
25 char *dst = frame_buf;
29 struct container_context *cntr;
32 // src: first channel in each of interleaved buffers in containers =>
34 for (i = 0; i < cntr_count; ++i) {
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);
43 memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
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)
53 char *src = frame_buf;
57 struct container_context *cntr;
60 for (i = 0; i < cntr_count; ++i) {
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;
69 memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
74 static int multiple_pre_process(struct mapper_context *mapper,
75 struct container_context *cntrs,
76 unsigned int cntr_count)
78 struct multiple_state *state = mapper->private_data;
79 struct container_context *cntr;
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) {
86 if (mapper->bytes_per_sample != cntr->bytes_per_sample)
89 state->cntr_count = cntr_count;
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;
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;
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) {
118 if (cntrs->samples_per_frame != 1)
123 state->bufs = calloc(cntr_count, sizeof(char *));
124 if (state->bufs == NULL)
127 for (i = 0; i < cntr_count; ++i) {
128 unsigned int bytes_per_buffer;
130 // Allocate intermediate buffer as the same size as a
131 // period for each of containers.
134 bytes_per_buffer = mapper->bytes_per_sample *
135 cntr->samples_per_frame *
136 mapper->frames_per_buffer;
138 state->bufs[i] = malloc(bytes_per_buffer);
139 if (state->bufs[i] == NULL)
141 memset(state->bufs[i], 0, bytes_per_buffer);
148 static int process_containers(char **src_bufs, unsigned int *frame_count,
149 struct container_context *cntrs,
150 unsigned int cntr_count)
152 struct container_context *cntr;
157 // TODO: arrangement for *frame_count.
158 for (i = 0; i < cntr_count; ++i) {
162 err = container_context_process_frames(cntr, src, frame_count);
170 static int multiple_muxer_process_frames(struct mapper_context *mapper,
172 unsigned int *frame_count,
173 struct container_context *cntrs,
174 unsigned int cntr_count)
176 struct multiple_state *state = mapper->private_data;
180 // If need to align PCM frames, process PCM frames to the intermediate
182 if (!state->align_frames) {
184 src_bufs = frame_buf;
186 src_bufs = state->bufs;
188 err = process_containers(src_bufs, frame_count, cntrs, cntr_count);
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,
202 static int multiple_demuxer_process_frames(struct mapper_context *mapper,
204 unsigned int *frame_count,
205 struct container_context *cntrs,
206 unsigned int cntr_count)
208 struct multiple_state *state = mapper->private_data;
211 // If need to align PCM frames, process PCM frames to the intermediate
213 if (!state->align_frames) {
215 dst_bufs = frame_buf;
217 dst_bufs = state->bufs;
218 state->align_frames(frame_buf, *frame_count, dst_bufs,
219 mapper->bytes_per_sample, cntrs,
223 return process_containers(dst_bufs, frame_count, cntrs, cntr_count);
226 static void multiple_post_process(struct mapper_context *mapper)
228 struct multiple_state *state = mapper->private_data;
232 for (i = 0; i < state->cntr_count; ++i) {
234 free(state->bufs[i]);
240 state->align_frames = NULL;
243 const struct mapper_data mapper_muxer_multiple = {
245 .pre_process = multiple_pre_process,
246 .process_frames = multiple_muxer_process_frames,
247 .post_process = multiple_post_process,
249 .private_size = sizeof(struct multiple_state),
252 const struct mapper_data mapper_demuxer_multiple = {
254 .pre_process = multiple_pre_process,
255 .process_frames = multiple_demuxer_process_frames,
256 .post_process = multiple_post_process,
258 .private_size = sizeof(struct multiple_state),