• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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