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