|
Packit Service |
a9274b |
// SPDX-License-Identifier: GPL-2.0
|
|
Packit Service |
a9274b |
//
|
|
Packit Service |
a9274b |
// mapper-multiple.c - a muxer/demuxer for multiple 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 multiple_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 |
struct container_context *cntrs,
|
|
Packit Service |
a9274b |
unsigned int cntr_count);
|
|
Packit Service |
a9274b |
char **bufs;
|
|
Packit Service |
a9274b |
unsigned int cntr_count;
|
|
Packit Service |
a9274b |
};
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static void align_to_i(void *frame_buf, unsigned int frame_count,
|
|
Packit Service |
a9274b |
char **src_bufs, unsigned int bytes_per_sample,
|
|
Packit Service |
a9274b |
struct container_context *cntrs, unsigned int cntr_count)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
char *dst = frame_buf;
|
|
Packit Service |
a9274b |
char *src;
|
|
Packit Service |
a9274b |
unsigned int dst_pos;
|
|
Packit Service |
a9274b |
unsigned int src_pos;
|
|
Packit Service |
a9274b |
struct container_context *cntr;
|
|
Packit Service |
a9274b |
int i, j;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// src: first channel in each of interleaved buffers in containers =>
|
|
Packit Service |
a9274b |
// dst:interleaved.
|
|
Packit Service |
a9274b |
for (i = 0; i < cntr_count; ++i) {
|
|
Packit Service |
a9274b |
src = src_bufs[i];
|
|
Packit Service |
a9274b |
cntr = cntrs + i;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
for (j = 0; j < frame_count; ++j) {
|
|
Packit Service |
a9274b |
// Use first src channel for each of dst channel.
|
|
Packit Service |
a9274b |
src_pos = bytes_per_sample * cntr->samples_per_frame * j;
|
|
Packit Service |
a9274b |
dst_pos = bytes_per_sample * (cntr_count * 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 void align_from_i(void *frame_buf, unsigned int frame_count,
|
|
Packit Service |
a9274b |
char **dst_bufs, unsigned int bytes_per_sample,
|
|
Packit Service |
a9274b |
struct container_context *cntrs,
|
|
Packit Service |
a9274b |
unsigned int cntr_count)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
char *src = frame_buf;
|
|
Packit Service |
a9274b |
char *dst;
|
|
Packit Service |
a9274b |
unsigned int src_pos;
|
|
Packit Service |
a9274b |
unsigned int dst_pos;
|
|
Packit Service |
a9274b |
struct container_context *cntr;
|
|
Packit Service |
a9274b |
int i, j;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
for (i = 0; i < cntr_count; ++i) {
|
|
Packit Service |
a9274b |
dst = dst_bufs[i];
|
|
Packit Service |
a9274b |
cntr = cntrs + i;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
for (j = 0; j < frame_count; ++j) {
|
|
Packit Service |
a9274b |
// Use first src channel for each of dst channel.
|
|
Packit Service |
a9274b |
src_pos = bytes_per_sample * (cntr_count * j + i);
|
|
Packit Service |
a9274b |
dst_pos = bytes_per_sample * cntr->samples_per_frame * 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 int multiple_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 multiple_state *state = mapper->private_data;
|
|
Packit Service |
a9274b |
struct container_context *cntr;
|
|
Packit Service |
a9274b |
int i;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Additionally, format of samples in the containers should be the same
|
|
Packit Service |
a9274b |
// as the format in PCM substream.
|
|
Packit Service |
a9274b |
for (i = 0; i < cntr_count; ++i) {
|
|
Packit Service |
a9274b |
cntr = cntrs + i;
|
|
Packit Service |
a9274b |
if (mapper->bytes_per_sample != cntr->bytes_per_sample)
|
|
Packit Service |
a9274b |
return -EINVAL;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
state->cntr_count = cntr_count;
|
|
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_INTERLEAVED ||
|
|
Packit Service |
a9274b |
mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
|
|
Packit Service |
a9274b |
state->align_frames = align_from_i;
|
|
Packit Service |
a9274b |
else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
|
|
Packit Service |
a9274b |
mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
|
|
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_INTERLEAVED ||
|
|
Packit Service |
a9274b |
mapper->access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
|
|
Packit Service |
a9274b |
state->align_frames = align_to_i;
|
|
Packit Service |
a9274b |
else if (mapper->access == SND_PCM_ACCESS_RW_NONINTERLEAVED ||
|
|
Packit Service |
a9274b |
mapper->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
|
|
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 |
// Furthermore, in demuxer case, each container should be
|
|
Packit Service |
a9274b |
// configured to store one sample per frame.
|
|
Packit Service |
a9274b |
if (mapper->type == MAPPER_TYPE_DEMUXER) {
|
|
Packit Service |
a9274b |
for (i = 0; i < cntr_count; ++i) {
|
|
Packit Service |
a9274b |
cntr = cntrs + i;
|
|
Packit Service |
a9274b |
if (cntr->samples_per_frame != 1)
|
|
Packit Service |
a9274b |
return -EINVAL;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
state->bufs = calloc(cntr_count, sizeof(char *));
|
|
Packit Service |
a9274b |
if (state->bufs == NULL)
|
|
Packit Service |
a9274b |
return -ENOMEM;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
for (i = 0; i < cntr_count; ++i) {
|
|
Packit Service |
a9274b |
unsigned int bytes_per_buffer;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Allocate intermediate buffer as the same size as a
|
|
Packit Service |
a9274b |
// period for each of containers.
|
|
Packit Service |
a9274b |
cntr = cntrs + i;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
bytes_per_buffer = mapper->bytes_per_sample *
|
|
Packit Service |
a9274b |
cntr->samples_per_frame *
|
|
Packit Service |
a9274b |
mapper->frames_per_buffer;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
state->bufs[i] = malloc(bytes_per_buffer);
|
|
Packit Service |
a9274b |
if (state->bufs[i] == NULL)
|
|
Packit Service |
a9274b |
return -ENOMEM;
|
|
Packit Service |
a9274b |
memset(state->bufs[i], 0, bytes_per_buffer);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int process_containers(char **src_bufs, 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 container_context *cntr;
|
|
Packit Service |
a9274b |
char *src;
|
|
Packit Service |
a9274b |
int i;
|
|
Packit Service |
a9274b |
int err = 0;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// TODO: arrangement for *frame_count.
|
|
Packit Service |
a9274b |
for (i = 0; i < cntr_count; ++i) {
|
|
Packit Service |
a9274b |
cntr = &cntrs[i];
|
|
Packit Service |
a9274b |
src = src_bufs[i];
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = container_context_process_frames(cntr, src, frame_count);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
break;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int multiple_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 multiple_state *state = mapper->private_data;
|
|
Packit Service |
a9274b |
char **src_bufs;
|
|
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_bufs = frame_buf;
|
|
Packit Service |
a9274b |
} else {
|
|
Packit Service |
a9274b |
src_bufs = state->bufs;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
err = process_containers(src_bufs, frame_count, cntrs, cntr_count);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Unlikely.
|
|
Packit Service |
a9274b |
if (src_bufs != frame_buf && *frame_count > 0) {
|
|
Packit Service |
a9274b |
state->align_frames(frame_buf, *frame_count, src_bufs,
|
|
Packit Service |
a9274b |
mapper->bytes_per_sample, cntrs,
|
|
Packit Service |
a9274b |
cntr_count);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int multiple_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 multiple_state *state = mapper->private_data;
|
|
Packit Service |
a9274b |
char **dst_bufs;
|
|
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_bufs = frame_buf;
|
|
Packit Service |
a9274b |
} else {
|
|
Packit Service |
a9274b |
dst_bufs = state->bufs;
|
|
Packit Service |
a9274b |
state->align_frames(frame_buf, *frame_count, dst_bufs,
|
|
Packit Service |
a9274b |
mapper->bytes_per_sample, cntrs,
|
|
Packit Service |
a9274b |
cntr_count);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return process_containers(dst_bufs, frame_count, cntrs, cntr_count);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static void multiple_post_process(struct mapper_context *mapper)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
struct multiple_state *state = mapper->private_data;
|
|
Packit Service |
a9274b |
int i;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (state->bufs) {
|
|
Packit Service |
a9274b |
for (i = 0; i < state->cntr_count; ++i) {
|
|
Packit Service |
a9274b |
if (state->bufs[i])
|
|
Packit Service |
a9274b |
free(state->bufs[i]);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
free(state->bufs);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
state->bufs = NULL;
|
|
Packit Service |
a9274b |
state->align_frames = NULL;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
const struct mapper_data mapper_muxer_multiple = {
|
|
Packit Service |
a9274b |
.ops = {
|
|
Packit Service |
a9274b |
.pre_process = multiple_pre_process,
|
|
Packit Service |
a9274b |
.process_frames = multiple_muxer_process_frames,
|
|
Packit Service |
a9274b |
.post_process = multiple_post_process,
|
|
Packit Service |
a9274b |
},
|
|
Packit Service |
a9274b |
.private_size = sizeof(struct multiple_state),
|
|
Packit Service |
a9274b |
};
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
const struct mapper_data mapper_demuxer_multiple = {
|
|
Packit Service |
a9274b |
.ops = {
|
|
Packit Service |
a9274b |
.pre_process = multiple_pre_process,
|
|
Packit Service |
a9274b |
.process_frames = multiple_demuxer_process_frames,
|
|
Packit Service |
a9274b |
.post_process = multiple_post_process,
|
|
Packit Service |
a9274b |
},
|
|
Packit Service |
a9274b |
.private_size = sizeof(struct multiple_state),
|
|
Packit Service |
a9274b |
};
|