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 12struct 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 19static 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 unsigned 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 41static 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 unsigned 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 63static int single_pre_process(struct mapper_context *mapper, 64 struct container_context *cntrs, 65 unsigned int cntr_count ATTRIBUTE_UNUSED) 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 109static 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 ATTRIBUTE_UNUSED) 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 140static 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 ATTRIBUTE_UNUSED) 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 164static 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 175const 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 184const 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