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