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