Blame axfer/mapper-multiple.c

Packit 229ac0
// SPDX-License-Identifier: GPL-2.0
Packit 229ac0
//
Packit 229ac0
// mapper-multiple.c - a muxer/demuxer for multiple containers.
Packit 229ac0
//
Packit 229ac0
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
Packit 229ac0
//
Packit 229ac0
// Licensed under the terms of the GNU General Public License, version 2.
Packit 229ac0
Packit 229ac0
#include "mapper.h"
Packit 229ac0
#include "misc.h"
Packit 229ac0
Packit 229ac0
struct multiple_state {
Packit 229ac0
	void (*align_frames)(void *frame_buf, unsigned int frame_count,
Packit 229ac0
			     char **buf, unsigned int bytes_per_sample,
Packit 229ac0
			     struct container_context *cntrs,
Packit 229ac0
			     unsigned int cntr_count);
Packit 229ac0
	char **bufs;
Packit 229ac0
	unsigned int cntr_count;
Packit 229ac0
};
Packit 229ac0
Packit 229ac0
static void align_to_i(void *frame_buf, unsigned int frame_count,
Packit 229ac0
		       char **src_bufs, unsigned int bytes_per_sample,
Packit 229ac0
		       struct container_context *cntrs, unsigned int cntr_count)
Packit 229ac0
{
Packit 229ac0
	char *dst = frame_buf;
Packit 229ac0
	char *src;
Packit 229ac0
	unsigned int dst_pos;
Packit 229ac0
	unsigned int src_pos;
Packit 229ac0
	struct container_context *cntr;
Packit 229ac0
	int i, j;
Packit 229ac0
Packit 229ac0
	// src: first channel in each of interleaved buffers in containers =>
Packit 229ac0
	// dst:interleaved.
Packit 229ac0
	for (i = 0; i < cntr_count; ++i) {
Packit 229ac0
		src = src_bufs[i];
Packit 229ac0
		cntr = cntrs + i;
Packit 229ac0
Packit 229ac0
		for (j = 0; j < frame_count; ++j) {
Packit 229ac0
			// Use first src channel for each of dst channel.
Packit 229ac0
			src_pos = bytes_per_sample * cntr->samples_per_frame * j;
Packit 229ac0
			dst_pos = bytes_per_sample * (cntr_count * j + i);
Packit 229ac0
Packit 229ac0
			memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
Packit 229ac0
		}
Packit 229ac0
	}
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void align_from_i(void *frame_buf, unsigned int frame_count,
Packit 229ac0
			 char **dst_bufs, unsigned int bytes_per_sample,
Packit 229ac0
			 struct container_context *cntrs,
Packit 229ac0
			 unsigned int cntr_count)
Packit 229ac0
{
Packit 229ac0
	char *src = frame_buf;
Packit 229ac0
	char *dst;
Packit 229ac0
	unsigned int src_pos;
Packit 229ac0
	unsigned int dst_pos;
Packit 229ac0
	struct container_context *cntr;
Packit 229ac0
	int i, j;
Packit 229ac0
Packit 229ac0
	for (i = 0; i < cntr_count; ++i) {
Packit 229ac0
		dst = dst_bufs[i];
Packit 229ac0
		cntr = cntrs + i;
Packit 229ac0
Packit 229ac0
		for (j = 0; j < frame_count; ++j) {
Packit 229ac0
			// Use first src channel for each of dst channel.
Packit 229ac0
			src_pos = bytes_per_sample * (cntr_count * j + i);
Packit 229ac0
			dst_pos = bytes_per_sample * cntr->samples_per_frame * j;
Packit 229ac0
Packit 229ac0
			memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
Packit 229ac0
		}
Packit 229ac0
	}
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static int multiple_pre_process(struct mapper_context *mapper,
Packit 229ac0
				struct container_context *cntrs,
Packit 229ac0
				unsigned int cntr_count)
Packit 229ac0
{
Packit 229ac0
	struct multiple_state *state = mapper->private_data;
Packit 229ac0
	struct container_context *cntr;
Packit 229ac0
	int i;
Packit 229ac0
Packit 229ac0
	// Additionally, format of samples in the containers should be the same
Packit 229ac0
	// as the format in PCM substream.
Packit 229ac0
	for (i = 0; i < cntr_count; ++i) {
Packit 229ac0
		cntr = cntrs + i;
Packit 229ac0
		if (mapper->bytes_per_sample != cntr->bytes_per_sample)
Packit 229ac0
			return -EINVAL;
Packit 229ac0
	}
Packit 229ac0
	state->cntr_count = cntr_count;
Packit 229ac0
Packit 229ac0
	// Decide method to align frames.
Packit 229ac0
	if (mapper->type == MAPPER_TYPE_DEMUXER) {
Packit 229ac0
		if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
Packit 229ac0
		    mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
Packit 229ac0
			state->align_frames = align_from_i;
Packit 229ac0
		else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
Packit 229ac0
			 mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
Packit 229ac0
			state->align_frames = NULL;
Packit 229ac0
		else
Packit 229ac0
			return -EINVAL;
Packit 229ac0
	} else {
Packit 229ac0
		if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
Packit 229ac0
		    mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
Packit 229ac0
			state->align_frames = align_to_i;
Packit 229ac0
		else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
Packit 229ac0
			 mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
Packit 229ac0
			state->align_frames = NULL;
Packit 229ac0
		else
Packit 229ac0
			return -EINVAL;
Packit 229ac0
	}
Packit 229ac0
Packit 229ac0
	if (state->align_frames) {
Packit 229ac0
		// Furthermore, in demuxer case, each container should be
Packit 229ac0
		// configured to store one sample per frame.
Packit 229ac0
		if (mapper->type == MAPPER_TYPE_DEMUXER) {
Packit 229ac0
			for (i = 0; i < cntr_count; ++i) {
Packit 229ac0
				cntr = cntrs + i;
Packit 229ac0
				if (cntr->samples_per_frame != 1)
Packit 229ac0
					return -EINVAL;
Packit 229ac0
			}
Packit 229ac0
		}
Packit 229ac0
Packit 229ac0
		state->bufs = calloc(cntr_count, sizeof(char *));
Packit 229ac0
		if (state->bufs == NULL)
Packit 229ac0
			return -ENOMEM;
Packit 229ac0
Packit 229ac0
		for (i = 0; i < cntr_count; ++i) {
Packit 229ac0
			unsigned int bytes_per_buffer;
Packit 229ac0
Packit 229ac0
			// Allocate intermediate buffer as the same size as a
Packit 229ac0
			// period for each of containers.
Packit 229ac0
			cntr = cntrs + i;
Packit 229ac0
Packit 229ac0
			bytes_per_buffer = mapper->bytes_per_sample *
Packit 229ac0
					   cntr->samples_per_frame *
Packit 229ac0
					   mapper->frames_per_buffer;
Packit 229ac0
Packit 229ac0
			state->bufs[i] = malloc(bytes_per_buffer);
Packit 229ac0
			if (state->bufs[i] == NULL)
Packit 229ac0
				return -ENOMEM;
Packit 229ac0
			memset(state->bufs[i], 0, bytes_per_buffer);
Packit 229ac0
		}
Packit 229ac0
	}
Packit 229ac0
Packit 229ac0
	return 0;
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static int process_containers(char **src_bufs, unsigned int *frame_count,
Packit 229ac0
			      struct container_context *cntrs,
Packit 229ac0
			      unsigned int cntr_count)
Packit 229ac0
{
Packit 229ac0
	struct container_context *cntr;
Packit 229ac0
	char *src;
Packit 229ac0
	int i;
Packit 229ac0
	int err = 0;
Packit 229ac0
Packit 229ac0
	// TODO: arrangement for *frame_count.
Packit 229ac0
	for (i = 0; i < cntr_count; ++i) {
Packit 229ac0
		cntr = &cntrs[i];
Packit 229ac0
		src = src_bufs[i];
Packit 229ac0
Packit 229ac0
		err = container_context_process_frames(cntr, src, frame_count);
Packit 229ac0
		if (err < 0)
Packit 229ac0
			break;
Packit 229ac0
	}
Packit 229ac0
Packit 229ac0
	return err;
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static int multiple_muxer_process_frames(struct mapper_context *mapper,
Packit 229ac0
					 void *frame_buf,
Packit 229ac0
					 unsigned int *frame_count,
Packit 229ac0
					 struct container_context *cntrs,
Packit 229ac0
					 unsigned int cntr_count)
Packit 229ac0
{
Packit 229ac0
	struct multiple_state *state = mapper->private_data;
Packit 229ac0
	char **src_bufs;
Packit 229ac0
	int err;
Packit 229ac0
Packit 229ac0
	// If need to align PCM frames, process PCM frames to the intermediate
Packit 229ac0
	// buffer once.
Packit 229ac0
	if (!state->align_frames) {
Packit 229ac0
		// The most likely.
Packit 229ac0
		src_bufs = frame_buf;
Packit 229ac0
	} else {
Packit 229ac0
		src_bufs = state->bufs;
Packit 229ac0
	}
Packit 229ac0
	err = process_containers(src_bufs, frame_count, cntrs, cntr_count);
Packit 229ac0
	if (err < 0)
Packit 229ac0
		return err;
Packit 229ac0
Packit 229ac0
	// Unlikely.
Packit 229ac0
	if (src_bufs != frame_buf && *frame_count > 0) {
Packit 229ac0
		state->align_frames(frame_buf, *frame_count, src_bufs,
Packit 229ac0
				    mapper->bytes_per_sample, cntrs,
Packit 229ac0
				    cntr_count);
Packit 229ac0
	}
Packit 229ac0
Packit 229ac0
	return 0;
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static int multiple_demuxer_process_frames(struct mapper_context *mapper,
Packit 229ac0
					   void *frame_buf,
Packit 229ac0
					   unsigned int *frame_count,
Packit 229ac0
					   struct container_context *cntrs,
Packit 229ac0
					   unsigned int cntr_count)
Packit 229ac0
{
Packit 229ac0
	struct multiple_state *state = mapper->private_data;
Packit 229ac0
	char **dst_bufs;
Packit 229ac0
Packit 229ac0
	// If need to align PCM frames, process PCM frames to the intermediate
Packit 229ac0
	// buffer once.
Packit 229ac0
	if (!state->align_frames) {
Packit 229ac0
		// The most likely.
Packit 229ac0
		dst_bufs = frame_buf;
Packit 229ac0
	} else {
Packit 229ac0
		dst_bufs = state->bufs;
Packit 229ac0
		state->align_frames(frame_buf, *frame_count, dst_bufs,
Packit 229ac0
				    mapper->bytes_per_sample, cntrs,
Packit 229ac0
				    cntr_count);
Packit 229ac0
	}
Packit 229ac0
Packit 229ac0
	return process_containers(dst_bufs, frame_count, cntrs, cntr_count);
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
static void multiple_post_process(struct mapper_context *mapper)
Packit 229ac0
{
Packit 229ac0
	struct multiple_state *state = mapper->private_data;
Packit 229ac0
	int i;
Packit 229ac0
Packit 229ac0
	if (state->bufs) {
Packit 229ac0
		for (i = 0; i < state->cntr_count; ++i) {
Packit 229ac0
			if (state->bufs[i])
Packit 229ac0
				free(state->bufs[i]);
Packit 229ac0
		}
Packit 229ac0
		free(state->bufs);
Packit 229ac0
	}
Packit 229ac0
Packit 229ac0
	state->bufs = NULL;
Packit 229ac0
	state->align_frames = NULL;
Packit 229ac0
}
Packit 229ac0
Packit 229ac0
const struct mapper_data mapper_muxer_multiple = {
Packit 229ac0
	.ops = {
Packit 229ac0
		.pre_process = multiple_pre_process,
Packit 229ac0
		.process_frames = multiple_muxer_process_frames,
Packit 229ac0
		.post_process = multiple_post_process,
Packit 229ac0
	},
Packit 229ac0
	.private_size = sizeof(struct multiple_state),
Packit 229ac0
};
Packit 229ac0
Packit 229ac0
const struct mapper_data mapper_demuxer_multiple = {
Packit 229ac0
	.ops = {
Packit 229ac0
		.pre_process = multiple_pre_process,
Packit 229ac0
		.process_frames = multiple_demuxer_process_frames,
Packit 229ac0
		.post_process = multiple_post_process,
Packit 229ac0
	},
Packit 229ac0
	.private_size = sizeof(struct multiple_state),
Packit 229ac0
};