1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2c72fcc34Sopenharmony_ci//
3c72fcc34Sopenharmony_ci// mapper-single.c - a muxer/demuxer for single 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 single_state {
13c72fcc34Sopenharmony_ci	void (*align_frames)(void *frame_buf, unsigned int frame_count,
14c72fcc34Sopenharmony_ci			     char *buf, unsigned int bytes_per_sample,
15c72fcc34Sopenharmony_ci			     unsigned int samples_per_frame);
16c72fcc34Sopenharmony_ci	char *buf;
17c72fcc34Sopenharmony_ci};
18c72fcc34Sopenharmony_ci
19c72fcc34Sopenharmony_cistatic void align_to_vector(void *frame_buf, unsigned int frame_count,
20c72fcc34Sopenharmony_ci			    char *src, unsigned int bytes_per_sample,
21c72fcc34Sopenharmony_ci			    unsigned samples_per_frame)
22c72fcc34Sopenharmony_ci{
23c72fcc34Sopenharmony_ci	char **dst_bufs = frame_buf;
24c72fcc34Sopenharmony_ci	char *dst;
25c72fcc34Sopenharmony_ci	unsigned int src_pos;
26c72fcc34Sopenharmony_ci	unsigned int dst_pos;
27c72fcc34Sopenharmony_ci	unsigned int i, j;
28c72fcc34Sopenharmony_ci
29c72fcc34Sopenharmony_ci	// src: interleaved => dst: a set of interleaved buffers.
30c72fcc34Sopenharmony_ci	for (i = 0; i < samples_per_frame; ++i) {
31c72fcc34Sopenharmony_ci		dst = dst_bufs[i];
32c72fcc34Sopenharmony_ci		for (j = 0; j < frame_count; ++j) {
33c72fcc34Sopenharmony_ci			src_pos = bytes_per_sample * (samples_per_frame * j + i);
34c72fcc34Sopenharmony_ci			dst_pos = bytes_per_sample * j;
35c72fcc34Sopenharmony_ci
36c72fcc34Sopenharmony_ci			memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
37c72fcc34Sopenharmony_ci		}
38c72fcc34Sopenharmony_ci	}
39c72fcc34Sopenharmony_ci}
40c72fcc34Sopenharmony_ci
41c72fcc34Sopenharmony_cistatic void align_from_vector(void *frame_buf, unsigned int frame_count,
42c72fcc34Sopenharmony_ci			      char *dst, unsigned int bytes_per_sample,
43c72fcc34Sopenharmony_ci			      unsigned int samples_per_frame)
44c72fcc34Sopenharmony_ci{
45c72fcc34Sopenharmony_ci	char **src_bufs = frame_buf;
46c72fcc34Sopenharmony_ci	char *src;
47c72fcc34Sopenharmony_ci	unsigned int dst_pos;
48c72fcc34Sopenharmony_ci	unsigned int src_pos;
49c72fcc34Sopenharmony_ci	unsigned int i, j;
50c72fcc34Sopenharmony_ci
51c72fcc34Sopenharmony_ci	// src: a set of interleaved buffers => dst:interleaved.
52c72fcc34Sopenharmony_ci	for (i = 0; i < samples_per_frame; ++i) {
53c72fcc34Sopenharmony_ci		src = src_bufs[i];
54c72fcc34Sopenharmony_ci		for (j = 0; j < frame_count; ++j) {
55c72fcc34Sopenharmony_ci			src_pos = bytes_per_sample * j;
56c72fcc34Sopenharmony_ci			dst_pos = bytes_per_sample * (samples_per_frame * j + i);
57c72fcc34Sopenharmony_ci
58c72fcc34Sopenharmony_ci			memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
59c72fcc34Sopenharmony_ci		}
60c72fcc34Sopenharmony_ci	}
61c72fcc34Sopenharmony_ci}
62c72fcc34Sopenharmony_ci
63c72fcc34Sopenharmony_cistatic int single_pre_process(struct mapper_context *mapper,
64c72fcc34Sopenharmony_ci			      struct container_context *cntrs,
65c72fcc34Sopenharmony_ci			      unsigned int cntr_count ATTRIBUTE_UNUSED)
66c72fcc34Sopenharmony_ci{
67c72fcc34Sopenharmony_ci	struct single_state *state = mapper->private_data;
68c72fcc34Sopenharmony_ci	unsigned int bytes_per_buffer;
69c72fcc34Sopenharmony_ci
70c72fcc34Sopenharmony_ci	if (cntrs->bytes_per_sample != mapper->bytes_per_sample ||
71c72fcc34Sopenharmony_ci	    cntrs->samples_per_frame != mapper->samples_per_frame)
72c72fcc34Sopenharmony_ci		return -EINVAL;
73c72fcc34Sopenharmony_ci
74c72fcc34Sopenharmony_ci	// Decide method to align frames.
75c72fcc34Sopenharmony_ci	if (mapper->type == MAPPER_TYPE_DEMUXER) {
76c72fcc34Sopenharmony_ci		if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
77c72fcc34Sopenharmony_ci		    mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
78c72fcc34Sopenharmony_ci			state->align_frames = align_from_vector;
79c72fcc34Sopenharmony_ci		else if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
80c72fcc34Sopenharmony_ci			 mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
81c72fcc34Sopenharmony_ci			state->align_frames = NULL;
82c72fcc34Sopenharmony_ci		else
83c72fcc34Sopenharmony_ci			return -EINVAL;
84c72fcc34Sopenharmony_ci	} else {
85c72fcc34Sopenharmony_ci		if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
86c72fcc34Sopenharmony_ci		    mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
87c72fcc34Sopenharmony_ci			state->align_frames = align_to_vector;
88c72fcc34Sopenharmony_ci		else if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
89c72fcc34Sopenharmony_ci			 mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
90c72fcc34Sopenharmony_ci			state->align_frames = NULL;
91c72fcc34Sopenharmony_ci		else
92c72fcc34Sopenharmony_ci			return -EINVAL;
93c72fcc34Sopenharmony_ci	}
94c72fcc34Sopenharmony_ci
95c72fcc34Sopenharmony_ci	if (state->align_frames) {
96c72fcc34Sopenharmony_ci		// Allocate intermediate buffer as the same size as a period.
97c72fcc34Sopenharmony_ci		bytes_per_buffer = mapper->bytes_per_sample *
98c72fcc34Sopenharmony_ci				   mapper->samples_per_frame *
99c72fcc34Sopenharmony_ci				   mapper->frames_per_buffer;
100c72fcc34Sopenharmony_ci		state->buf = malloc(bytes_per_buffer);
101c72fcc34Sopenharmony_ci		if (state->buf == NULL)
102c72fcc34Sopenharmony_ci			return -ENOMEM;
103c72fcc34Sopenharmony_ci		memset(state->buf, 0, bytes_per_buffer);
104c72fcc34Sopenharmony_ci	}
105c72fcc34Sopenharmony_ci
106c72fcc34Sopenharmony_ci	return 0;
107c72fcc34Sopenharmony_ci}
108c72fcc34Sopenharmony_ci
109c72fcc34Sopenharmony_cistatic int single_muxer_process_frames(struct mapper_context *mapper,
110c72fcc34Sopenharmony_ci				       void *frame_buf,
111c72fcc34Sopenharmony_ci				       unsigned int *frame_count,
112c72fcc34Sopenharmony_ci				       struct container_context *cntrs,
113c72fcc34Sopenharmony_ci				       unsigned int cntr_count ATTRIBUTE_UNUSED)
114c72fcc34Sopenharmony_ci{
115c72fcc34Sopenharmony_ci	struct single_state *state = mapper->private_data;
116c72fcc34Sopenharmony_ci	void *src;
117c72fcc34Sopenharmony_ci	int err;
118c72fcc34Sopenharmony_ci
119c72fcc34Sopenharmony_ci	// If need to align PCM frames, process PCM frames to the intermediate
120c72fcc34Sopenharmony_ci	// buffer once.
121c72fcc34Sopenharmony_ci	if (!state->align_frames) {
122c72fcc34Sopenharmony_ci		// The most likely.
123c72fcc34Sopenharmony_ci		src = frame_buf;
124c72fcc34Sopenharmony_ci	} else {
125c72fcc34Sopenharmony_ci		src = state->buf;
126c72fcc34Sopenharmony_ci	}
127c72fcc34Sopenharmony_ci	err = container_context_process_frames(cntrs, src, frame_count);
128c72fcc34Sopenharmony_ci	if (err < 0)
129c72fcc34Sopenharmony_ci		return err;
130c72fcc34Sopenharmony_ci
131c72fcc34Sopenharmony_ci	// Unlikely.
132c72fcc34Sopenharmony_ci	if (src != frame_buf && *frame_count > 0)
133c72fcc34Sopenharmony_ci		state->align_frames(frame_buf, *frame_count, src,
134c72fcc34Sopenharmony_ci				    mapper->bytes_per_sample,
135c72fcc34Sopenharmony_ci				    mapper->samples_per_frame);
136c72fcc34Sopenharmony_ci
137c72fcc34Sopenharmony_ci	return 0;
138c72fcc34Sopenharmony_ci}
139c72fcc34Sopenharmony_ci
140c72fcc34Sopenharmony_cistatic int single_demuxer_process_frames(struct mapper_context *mapper,
141c72fcc34Sopenharmony_ci					 void *frame_buf,
142c72fcc34Sopenharmony_ci					 unsigned int *frame_count,
143c72fcc34Sopenharmony_ci					 struct container_context *cntrs,
144c72fcc34Sopenharmony_ci					 unsigned int cntr_count ATTRIBUTE_UNUSED)
145c72fcc34Sopenharmony_ci{
146c72fcc34Sopenharmony_ci	struct single_state *state = mapper->private_data;
147c72fcc34Sopenharmony_ci	void *dst;
148c72fcc34Sopenharmony_ci
149c72fcc34Sopenharmony_ci	// If need to align PCM frames, process PCM frames to the intermediate
150c72fcc34Sopenharmony_ci	// buffer once.
151c72fcc34Sopenharmony_ci	if (!state->align_frames) {
152c72fcc34Sopenharmony_ci		// The most likely.
153c72fcc34Sopenharmony_ci		dst = frame_buf;
154c72fcc34Sopenharmony_ci	} else {
155c72fcc34Sopenharmony_ci		state->align_frames(frame_buf, *frame_count, state->buf,
156c72fcc34Sopenharmony_ci				    mapper->bytes_per_sample,
157c72fcc34Sopenharmony_ci				    mapper->samples_per_frame);
158c72fcc34Sopenharmony_ci		dst = state->buf;
159c72fcc34Sopenharmony_ci	}
160c72fcc34Sopenharmony_ci
161c72fcc34Sopenharmony_ci	return container_context_process_frames(cntrs, dst, frame_count);
162c72fcc34Sopenharmony_ci}
163c72fcc34Sopenharmony_ci
164c72fcc34Sopenharmony_cistatic void single_post_process(struct mapper_context *mapper)
165c72fcc34Sopenharmony_ci{
166c72fcc34Sopenharmony_ci	struct single_state *state = mapper->private_data;
167c72fcc34Sopenharmony_ci
168c72fcc34Sopenharmony_ci	if (state->buf)
169c72fcc34Sopenharmony_ci		free(state->buf);
170c72fcc34Sopenharmony_ci
171c72fcc34Sopenharmony_ci	state->buf = NULL;
172c72fcc34Sopenharmony_ci	state->align_frames = NULL;
173c72fcc34Sopenharmony_ci}
174c72fcc34Sopenharmony_ci
175c72fcc34Sopenharmony_ciconst struct mapper_data mapper_muxer_single = {
176c72fcc34Sopenharmony_ci	.ops = {
177c72fcc34Sopenharmony_ci		.pre_process = single_pre_process,
178c72fcc34Sopenharmony_ci		.process_frames = single_muxer_process_frames,
179c72fcc34Sopenharmony_ci		.post_process = single_post_process,
180c72fcc34Sopenharmony_ci	},
181c72fcc34Sopenharmony_ci	.private_size = sizeof(struct single_state),
182c72fcc34Sopenharmony_ci};
183c72fcc34Sopenharmony_ci
184c72fcc34Sopenharmony_ciconst struct mapper_data mapper_demuxer_single = {
185c72fcc34Sopenharmony_ci	.ops = {
186c72fcc34Sopenharmony_ci		.pre_process = single_pre_process,
187c72fcc34Sopenharmony_ci		.process_frames = single_demuxer_process_frames,
188c72fcc34Sopenharmony_ci		.post_process = single_post_process,
189c72fcc34Sopenharmony_ci	},
190c72fcc34Sopenharmony_ci	.private_size = sizeof(struct single_state),
191c72fcc34Sopenharmony_ci};
192