mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 04:05:43 +01:00
axfer: add support for a container of raw data
This commit adds support for raw data without any headers/chunks/blocks. A parser of container cannot recognize format of sample without supplemental information. Additionally, it includes no magic bytes. A parser of container should process first several bytes as a part of PCM frames, instead of magic bytes. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
4ab7510f3a
commit
96110793b3
4 changed files with 103 additions and 7 deletions
|
@ -27,4 +27,5 @@ axfer_SOURCES = \
|
||||||
container.c \
|
container.c \
|
||||||
container-riff-wave.c \
|
container-riff-wave.c \
|
||||||
container-au.c \
|
container-au.c \
|
||||||
container-voc.c
|
container-voc.c \
|
||||||
|
container-raw.c
|
||||||
|
|
66
axfer/container-raw.c
Normal file
66
axfer/container-raw.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
//
|
||||||
|
// container-raw.c - a parser/builder for a container with raw data frame.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
|
||||||
|
//
|
||||||
|
// Licensed under the terms of the GNU General Public License, version 2.
|
||||||
|
|
||||||
|
#include "container.h"
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static int raw_builder_pre_process(struct container_context *cntr,
|
||||||
|
snd_pcm_format_t *sample_format,
|
||||||
|
unsigned int *samples_per_frame,
|
||||||
|
unsigned int *frames_per_second,
|
||||||
|
uint64_t *byte_count)
|
||||||
|
{
|
||||||
|
*byte_count = UINT64_MAX;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int raw_parser_pre_process(struct container_context *cntr,
|
||||||
|
snd_pcm_format_t *sample_format,
|
||||||
|
unsigned int *samples_per_frame,
|
||||||
|
unsigned int *frames_per_second,
|
||||||
|
uint64_t *byte_count)
|
||||||
|
{
|
||||||
|
struct stat buf = {0};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (cntr->stdio) {
|
||||||
|
*byte_count = UINT64_MAX;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fstat(cntr->fd, &buf);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
*byte_count = buf.st_size;
|
||||||
|
if (*byte_count == 0)
|
||||||
|
*byte_count = UINT64_MAX;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct container_parser container_parser_raw = {
|
||||||
|
.format = CONTAINER_FORMAT_RAW,
|
||||||
|
.max_size = UINT64_MAX,
|
||||||
|
.ops = {
|
||||||
|
.pre_process = raw_parser_pre_process,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct container_builder container_builder_raw = {
|
||||||
|
.format = CONTAINER_FORMAT_RAW,
|
||||||
|
.max_size = UINT64_MAX,
|
||||||
|
.ops = {
|
||||||
|
.pre_process = raw_builder_pre_process,
|
||||||
|
},
|
||||||
|
};
|
|
@ -23,15 +23,16 @@ static const char *const cntr_format_labels[] = {
|
||||||
[CONTAINER_FORMAT_RIFF_WAVE] = "riff/wave",
|
[CONTAINER_FORMAT_RIFF_WAVE] = "riff/wave",
|
||||||
[CONTAINER_FORMAT_AU] = "au",
|
[CONTAINER_FORMAT_AU] = "au",
|
||||||
[CONTAINER_FORMAT_VOC] = "voc",
|
[CONTAINER_FORMAT_VOC] = "voc",
|
||||||
|
[CONTAINER_FORMAT_RAW] = "raw",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const suffixes[] = {
|
static const char *const suffixes[] = {
|
||||||
[CONTAINER_FORMAT_RIFF_WAVE] = ".wav",
|
[CONTAINER_FORMAT_RIFF_WAVE] = ".wav",
|
||||||
[CONTAINER_FORMAT_AU] = ".au",
|
[CONTAINER_FORMAT_AU] = ".au",
|
||||||
[CONTAINER_FORMAT_VOC] = ".voc",
|
[CONTAINER_FORMAT_VOC] = ".voc",
|
||||||
|
[CONTAINER_FORMAT_RAW] = "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const char *const container_suffix_from_format(enum container_format format)
|
const char *const container_suffix_from_format(enum container_format format)
|
||||||
{
|
{
|
||||||
return suffixes[format];
|
return suffixes[format];
|
||||||
|
@ -108,7 +109,7 @@ enum container_format container_format_from_path(const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsupported.
|
// Unsupported.
|
||||||
return CONTAINER_FORMAT_COUNT;
|
return CONTAINER_FORMAT_RAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
int container_seek_offset(struct container_context *cntr, off64_t offset)
|
int container_seek_offset(struct container_context *cntr, off64_t offset)
|
||||||
|
@ -196,7 +197,7 @@ int container_parser_init(struct container_context *cntr,
|
||||||
|
|
||||||
// Unless detected, use raw container.
|
// Unless detected, use raw container.
|
||||||
if (i == ARRAY_SIZE(parsers))
|
if (i == ARRAY_SIZE(parsers))
|
||||||
return -EINVAL;
|
parser = &container_parser_raw;
|
||||||
|
|
||||||
// Allocate private data for the parser.
|
// Allocate private data for the parser.
|
||||||
if (parser->private_size > 0) {
|
if (parser->private_size > 0) {
|
||||||
|
@ -224,6 +225,7 @@ int container_builder_init(struct container_context *cntr,
|
||||||
[CONTAINER_FORMAT_RIFF_WAVE] = &container_builder_riff_wave,
|
[CONTAINER_FORMAT_RIFF_WAVE] = &container_builder_riff_wave,
|
||||||
[CONTAINER_FORMAT_AU] = &container_builder_au,
|
[CONTAINER_FORMAT_AU] = &container_builder_au,
|
||||||
[CONTAINER_FORMAT_VOC] = &container_builder_voc,
|
[CONTAINER_FORMAT_VOC] = &container_builder_voc,
|
||||||
|
[CONTAINER_FORMAT_RAW] = &container_builder_raw,
|
||||||
};
|
};
|
||||||
const struct container_builder *builder;
|
const struct container_builder *builder;
|
||||||
int err;
|
int err;
|
||||||
|
@ -302,6 +304,16 @@ int container_context_pre_process(struct container_context *cntr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cntr->format == CONTAINER_FORMAT_RAW) {
|
||||||
|
if (*format == SND_PCM_FORMAT_UNKNOWN ||
|
||||||
|
*samples_per_frame == 0 || *frames_per_second == 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Any file format is not detected. Need to "
|
||||||
|
"indicate all of sample format, channels and "
|
||||||
|
"rate explicitly.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
assert(*format >= SND_PCM_FORMAT_S8);
|
assert(*format >= SND_PCM_FORMAT_S8);
|
||||||
assert(*format <= SND_PCM_FORMAT_LAST);
|
assert(*format <= SND_PCM_FORMAT_LAST);
|
||||||
assert(*samples_per_frame > 0);
|
assert(*samples_per_frame > 0);
|
||||||
|
@ -348,6 +360,7 @@ int container_context_process_frames(struct container_context *cntr,
|
||||||
char *buf = frame_buffer;
|
char *buf = frame_buffer;
|
||||||
unsigned int bytes_per_frame;
|
unsigned int bytes_per_frame;
|
||||||
unsigned int byte_count;
|
unsigned int byte_count;
|
||||||
|
unsigned int target_byte_count;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
assert(cntr);
|
assert(cntr);
|
||||||
|
@ -356,7 +369,19 @@ int container_context_process_frames(struct container_context *cntr,
|
||||||
assert(frame_count);
|
assert(frame_count);
|
||||||
|
|
||||||
bytes_per_frame = cntr->bytes_per_sample * cntr->samples_per_frame;
|
bytes_per_frame = cntr->bytes_per_sample * cntr->samples_per_frame;
|
||||||
byte_count = *frame_count * bytes_per_frame;
|
target_byte_count = *frame_count * bytes_per_frame;
|
||||||
|
|
||||||
|
// A parser of cotainers already read first 4 bytes to detect format
|
||||||
|
// of container, however they includes PCM frames when any format was
|
||||||
|
// undetected. Surely to write out them.
|
||||||
|
byte_count = target_byte_count;
|
||||||
|
if (cntr->format == CONTAINER_FORMAT_RAW &&
|
||||||
|
cntr->type == CONTAINER_TYPE_PARSER && !cntr->magic_handled) {
|
||||||
|
memcpy(buf, cntr->magic, sizeof(cntr->magic));
|
||||||
|
buf += sizeof(cntr->magic);
|
||||||
|
byte_count -= sizeof(cntr->magic);
|
||||||
|
cntr->magic_handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Each container has limitation for its volume for sample data.
|
// Each container has limitation for its volume for sample data.
|
||||||
if (cntr->handled_byte_count > cntr->max_size - byte_count)
|
if (cntr->handled_byte_count > cntr->max_size - byte_count)
|
||||||
|
@ -370,11 +395,11 @@ int container_context_process_frames(struct container_context *cntr,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
cntr->handled_byte_count += byte_count;
|
cntr->handled_byte_count += target_byte_count;
|
||||||
if (cntr->handled_byte_count == cntr->max_size)
|
if (cntr->handled_byte_count == cntr->max_size)
|
||||||
cntr->eof = true;
|
cntr->eof = true;
|
||||||
|
|
||||||
*frame_count = byte_count / bytes_per_frame;
|
*frame_count = target_byte_count / bytes_per_frame;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum container_format {
|
||||||
CONTAINER_FORMAT_RIFF_WAVE = 0,
|
CONTAINER_FORMAT_RIFF_WAVE = 0,
|
||||||
CONTAINER_FORMAT_AU,
|
CONTAINER_FORMAT_AU,
|
||||||
CONTAINER_FORMAT_VOC,
|
CONTAINER_FORMAT_VOC,
|
||||||
|
CONTAINER_FORMAT_RAW,
|
||||||
CONTAINER_FORMAT_COUNT,
|
CONTAINER_FORMAT_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -119,4 +120,7 @@ extern const struct container_builder container_builder_au;
|
||||||
extern const struct container_parser container_parser_voc;
|
extern const struct container_parser container_parser_voc;
|
||||||
extern const struct container_builder container_builder_voc;
|
extern const struct container_builder container_builder_voc;
|
||||||
|
|
||||||
|
const struct container_parser container_parser_raw;
|
||||||
|
const struct container_builder container_builder_raw;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue