Blame axfer/mapper-single.c

Packit Service a9274b
// SPDX-License-Identifier: GPL-2.0
Packit Service a9274b
//
Packit Service a9274b
// mapper-single.c - a muxer/demuxer for single containers.
Packit Service a9274b
//
Packit Service a9274b
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
Packit Service a9274b
//
Packit Service a9274b
// Licensed under the terms of the GNU General Public License, version 2.
Packit Service a9274b
Packit Service a9274b
#include "mapper.h"
Packit Service a9274b
#include "misc.h"
Packit Service a9274b
Packit Service a9274b
struct single_state {
Packit Service a9274b
	void (*align_frames)(void *frame_buf, unsigned int frame_count,
Packit Service a9274b
			     char *buf, unsigned int bytes_per_sample,
Packit Service a9274b
			     unsigned int samples_per_frame);
Packit Service a9274b
	char *buf;
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static void align_to_vector(void *frame_buf, unsigned int frame_count,
Packit Service a9274b
			    char *src, unsigned int bytes_per_sample,
Packit Service a9274b
			    unsigned samples_per_frame)
Packit Service a9274b
{
Packit Service a9274b
	char **dst_bufs = frame_buf;
Packit Service a9274b
	char *dst;
Packit Service a9274b
	unsigned int src_pos;
Packit Service a9274b
	unsigned int dst_pos;
Packit Service a9274b
	int i, j;
Packit Service a9274b
Packit Service a9274b
	// src: interleaved => dst: a set of interleaved buffers.
Packit Service a9274b
	for (i = 0; i < samples_per_frame; ++i) {
Packit Service a9274b
		dst = dst_bufs[i];
Packit Service a9274b
		for (j = 0; j < frame_count; ++j) {
Packit Service a9274b
			src_pos = bytes_per_sample * (samples_per_frame * j + i);
Packit Service a9274b
			dst_pos = bytes_per_sample * j;
Packit Service a9274b
Packit Service a9274b
			memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void align_from_vector(void *frame_buf, unsigned int frame_count,
Packit Service a9274b
			      char *dst, unsigned int bytes_per_sample,
Packit Service a9274b
			      unsigned int samples_per_frame)
Packit Service a9274b
{
Packit Service a9274b
	char **src_bufs = frame_buf;
Packit Service a9274b
	char *src;
Packit Service a9274b
	unsigned int dst_pos;
Packit Service a9274b
	unsigned int src_pos;
Packit Service a9274b
	int i, j;
Packit Service a9274b
Packit Service a9274b
	// src: a set of interleaved buffers => dst:interleaved.
Packit Service a9274b
	for (i = 0; i < samples_per_frame; ++i) {
Packit Service a9274b
		src = src_bufs[i];
Packit Service a9274b
		for (j = 0; j < frame_count; ++j) {
Packit Service a9274b
			src_pos = bytes_per_sample * j;
Packit Service a9274b
			dst_pos = bytes_per_sample * (samples_per_frame * j + i);
Packit Service a9274b
Packit Service a9274b
			memcpy(dst + dst_pos, src + src_pos, bytes_per_sample);
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int single_pre_process(struct mapper_context *mapper,
Packit Service a9274b
			      struct container_context *cntrs,
Packit Service a9274b
			      unsigned int cntr_count)
Packit Service a9274b
{
Packit Service a9274b
	struct single_state *state = mapper->private_data;
Packit Service a9274b
	unsigned int bytes_per_buffer;
Packit Service a9274b
Packit Service a9274b
	if (cntrs->bytes_per_sample != mapper->bytes_per_sample ||
Packit Service a9274b
	    cntrs->samples_per_frame != mapper->samples_per_frame)
Packit Service a9274b
		return -EINVAL;
Packit Service a9274b
Packit Service a9274b
	// Decide method to align frames.
Packit Service a9274b
	if (mapper->type == MAPPER_TYPE_DEMUXER) {
Packit Service a9274b
		if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
Packit Service a9274b
		    mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
Packit Service a9274b
			state->align_frames = align_from_vector;
Packit Service a9274b
		else if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
Packit Service a9274b
			 mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
Packit Service a9274b
			state->align_frames = NULL;
Packit Service a9274b
		else
Packit Service a9274b
			return -EINVAL;
Packit Service a9274b
	} else {
Packit Service a9274b
		if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
Packit Service a9274b
		    mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
Packit Service a9274b
			state->align_frames = align_to_vector;
Packit Service a9274b
		else if (mapper->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
Packit Service a9274b
			 mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
Packit Service a9274b
			state->align_frames = NULL;
Packit Service a9274b
		else
Packit Service a9274b
			return -EINVAL;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (state->align_frames) {
Packit Service a9274b
		// Allocate intermediate buffer as the same size as a period.
Packit Service a9274b
		bytes_per_buffer = mapper->bytes_per_sample *
Packit Service a9274b
				   mapper->samples_per_frame *
Packit Service a9274b
				   mapper->frames_per_buffer;
Packit Service a9274b
		state->buf = malloc(bytes_per_buffer);
Packit Service a9274b
		if (state->buf == NULL)
Packit Service a9274b
			return -ENOMEM;
Packit Service a9274b
		memset(state->buf, 0, bytes_per_buffer);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int single_muxer_process_frames(struct mapper_context *mapper,
Packit Service a9274b
				       void *frame_buf,
Packit Service a9274b
				       unsigned int *frame_count,
Packit Service a9274b
				       struct container_context *cntrs,
Packit Service a9274b
				       unsigned int cntr_count)
Packit Service a9274b
{
Packit Service a9274b
	struct single_state *state = mapper->private_data;
Packit Service a9274b
	void *src;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	// If need to align PCM frames, process PCM frames to the intermediate
Packit Service a9274b
	// buffer once.
Packit Service a9274b
	if (!state->align_frames) {
Packit Service a9274b
		// The most likely.
Packit Service a9274b
		src = frame_buf;
Packit Service a9274b
	} else {
Packit Service a9274b
		src = state->buf;
Packit Service a9274b
	}
Packit Service a9274b
	err = container_context_process_frames(cntrs, src, frame_count);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return err;
Packit Service a9274b
Packit Service a9274b
	// Unlikely.
Packit Service a9274b
	if (src != frame_buf && *frame_count > 0)
Packit Service a9274b
		state->align_frames(frame_buf, *frame_count, src,
Packit Service a9274b
				    mapper->bytes_per_sample,
Packit Service a9274b
				    mapper->samples_per_frame);
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int single_demuxer_process_frames(struct mapper_context *mapper,
Packit Service a9274b
					 void *frame_buf,
Packit Service a9274b
					 unsigned int *frame_count,
Packit Service a9274b
					 struct container_context *cntrs,
Packit Service a9274b
					 unsigned int cntr_count)
Packit Service a9274b
{
Packit Service a9274b
	struct single_state *state = mapper->private_data;
Packit Service a9274b
	void *dst;
Packit Service a9274b
Packit Service a9274b
	// If need to align PCM frames, process PCM frames to the intermediate
Packit Service a9274b
	// buffer once.
Packit Service a9274b
	if (!state->align_frames) {
Packit Service a9274b
		// The most likely.
Packit Service a9274b
		dst = frame_buf;
Packit Service a9274b
	} else {
Packit Service a9274b
		state->align_frames(frame_buf, *frame_count, state->buf,
Packit Service a9274b
				    mapper->bytes_per_sample,
Packit Service a9274b
				    mapper->samples_per_frame);
Packit Service a9274b
		dst = state->buf;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return container_context_process_frames(cntrs, dst, frame_count);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void single_post_process(struct mapper_context *mapper)
Packit Service a9274b
{
Packit Service a9274b
	struct single_state *state = mapper->private_data;
Packit Service a9274b
Packit Service a9274b
	if (state->buf)
Packit Service a9274b
		free(state->buf);
Packit Service a9274b
Packit Service a9274b
	state->buf = NULL;
Packit Service a9274b
	state->align_frames = NULL;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
const struct mapper_data mapper_muxer_single = {
Packit Service a9274b
	.ops = {
Packit Service a9274b
		.pre_process = single_pre_process,
Packit Service a9274b
		.process_frames = single_muxer_process_frames,
Packit Service a9274b
		.post_process = single_post_process,
Packit Service a9274b
	},
Packit Service a9274b
	.private_size = sizeof(struct single_state),
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
const struct mapper_data mapper_demuxer_single = {
Packit Service a9274b
	.ops = {
Packit Service a9274b
		.pre_process = single_pre_process,
Packit Service a9274b
		.process_frames = single_demuxer_process_frames,
Packit Service a9274b
		.post_process = single_post_process,
Packit Service a9274b
	},
Packit Service a9274b
	.private_size = sizeof(struct single_state),
Packit Service a9274b
};