1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// container.c - an interface of parser/builder for formatted files. 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 "container.h" 10c72fcc34Sopenharmony_ci#include "misc.h" 11c72fcc34Sopenharmony_ci 12c72fcc34Sopenharmony_ci#include <stdio.h> 13c72fcc34Sopenharmony_ci#include <errno.h> 14c72fcc34Sopenharmony_ci#include <string.h> 15c72fcc34Sopenharmony_ci#include <fcntl.h> 16c72fcc34Sopenharmony_ci#include <inttypes.h> 17c72fcc34Sopenharmony_ci 18c72fcc34Sopenharmony_cistatic const char *const cntr_type_labels[] = { 19c72fcc34Sopenharmony_ci [CONTAINER_TYPE_PARSER] = "parser", 20c72fcc34Sopenharmony_ci [CONTAINER_TYPE_BUILDER] = "builder", 21c72fcc34Sopenharmony_ci}; 22c72fcc34Sopenharmony_ci 23c72fcc34Sopenharmony_cistatic const char *const cntr_format_labels[] = { 24c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_RIFF_WAVE] = "riff/wave", 25c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_AU] = "au", 26c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_VOC] = "voc", 27c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_RAW] = "raw", 28c72fcc34Sopenharmony_ci}; 29c72fcc34Sopenharmony_ci 30c72fcc34Sopenharmony_cistatic const char *const suffixes[] = { 31c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_RIFF_WAVE] = ".wav", 32c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_AU] = ".au", 33c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_VOC] = ".voc", 34c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_RAW] = "", 35c72fcc34Sopenharmony_ci}; 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_ciconst char * container_suffix_from_format(enum container_format format) 38c72fcc34Sopenharmony_ci{ 39c72fcc34Sopenharmony_ci return suffixes[format]; 40c72fcc34Sopenharmony_ci} 41c72fcc34Sopenharmony_ci 42c72fcc34Sopenharmony_ciint container_recursive_read(struct container_context *cntr, void *buf, 43c72fcc34Sopenharmony_ci unsigned int byte_count) 44c72fcc34Sopenharmony_ci{ 45c72fcc34Sopenharmony_ci char *dst = buf; 46c72fcc34Sopenharmony_ci ssize_t result; 47c72fcc34Sopenharmony_ci size_t consumed = 0; 48c72fcc34Sopenharmony_ci 49c72fcc34Sopenharmony_ci while (consumed < byte_count && !cntr->interrupted) { 50c72fcc34Sopenharmony_ci result = read(cntr->fd, dst + consumed, byte_count - consumed); 51c72fcc34Sopenharmony_ci if (result < 0) { 52c72fcc34Sopenharmony_ci // This descriptor was configured with non-blocking 53c72fcc34Sopenharmony_ci // mode. EINTR is not cought when get any interrupts. 54c72fcc34Sopenharmony_ci if (cntr->interrupted) 55c72fcc34Sopenharmony_ci return -EINTR; 56c72fcc34Sopenharmony_ci if (errno == EAGAIN) 57c72fcc34Sopenharmony_ci continue; 58c72fcc34Sopenharmony_ci return -errno; 59c72fcc34Sopenharmony_ci } 60c72fcc34Sopenharmony_ci // Reach EOF. 61c72fcc34Sopenharmony_ci if (result == 0) { 62c72fcc34Sopenharmony_ci cntr->eof = true; 63c72fcc34Sopenharmony_ci return 0; 64c72fcc34Sopenharmony_ci } 65c72fcc34Sopenharmony_ci 66c72fcc34Sopenharmony_ci consumed += result; 67c72fcc34Sopenharmony_ci } 68c72fcc34Sopenharmony_ci 69c72fcc34Sopenharmony_ci return 0; 70c72fcc34Sopenharmony_ci} 71c72fcc34Sopenharmony_ci 72c72fcc34Sopenharmony_ciint container_recursive_write(struct container_context *cntr, void *buf, 73c72fcc34Sopenharmony_ci unsigned int byte_count) 74c72fcc34Sopenharmony_ci{ 75c72fcc34Sopenharmony_ci char *src = buf; 76c72fcc34Sopenharmony_ci ssize_t result; 77c72fcc34Sopenharmony_ci size_t consumed = 0; 78c72fcc34Sopenharmony_ci 79c72fcc34Sopenharmony_ci while (consumed < byte_count && !cntr->interrupted) { 80c72fcc34Sopenharmony_ci result = write(cntr->fd, src + consumed, byte_count - consumed); 81c72fcc34Sopenharmony_ci if (result < 0) { 82c72fcc34Sopenharmony_ci // This descriptor was configured with non-blocking 83c72fcc34Sopenharmony_ci // mode. EINTR is not cought when get any interrupts. 84c72fcc34Sopenharmony_ci if (cntr->interrupted) 85c72fcc34Sopenharmony_ci return -EINTR; 86c72fcc34Sopenharmony_ci if (errno == EAGAIN) 87c72fcc34Sopenharmony_ci continue; 88c72fcc34Sopenharmony_ci return -errno; 89c72fcc34Sopenharmony_ci } 90c72fcc34Sopenharmony_ci 91c72fcc34Sopenharmony_ci consumed += result; 92c72fcc34Sopenharmony_ci } 93c72fcc34Sopenharmony_ci 94c72fcc34Sopenharmony_ci return 0; 95c72fcc34Sopenharmony_ci} 96c72fcc34Sopenharmony_ci 97c72fcc34Sopenharmony_cienum container_format container_format_from_path(const char *path) 98c72fcc34Sopenharmony_ci{ 99c72fcc34Sopenharmony_ci const char *suffix; 100c72fcc34Sopenharmony_ci const char *pos; 101c72fcc34Sopenharmony_ci int i; 102c72fcc34Sopenharmony_ci 103c72fcc34Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(suffixes); ++i) { 104c72fcc34Sopenharmony_ci suffix = suffixes[i]; 105c72fcc34Sopenharmony_ci 106c72fcc34Sopenharmony_ci // Check last part of the string. 107c72fcc34Sopenharmony_ci pos = path + strlen(path) - strlen(suffix); 108c72fcc34Sopenharmony_ci if (!strcmp(pos, suffix)) 109c72fcc34Sopenharmony_ci return i; 110c72fcc34Sopenharmony_ci } 111c72fcc34Sopenharmony_ci 112c72fcc34Sopenharmony_ci // Unsupported. 113c72fcc34Sopenharmony_ci return CONTAINER_FORMAT_RAW; 114c72fcc34Sopenharmony_ci} 115c72fcc34Sopenharmony_ci 116c72fcc34Sopenharmony_ciint container_seek_offset(struct container_context *cntr, off_t offset) 117c72fcc34Sopenharmony_ci{ 118c72fcc34Sopenharmony_ci off_t pos; 119c72fcc34Sopenharmony_ci 120c72fcc34Sopenharmony_ci pos = lseek(cntr->fd, offset, SEEK_SET); 121c72fcc34Sopenharmony_ci if (pos < 0) 122c72fcc34Sopenharmony_ci return -errno; 123c72fcc34Sopenharmony_ci if (pos != offset) 124c72fcc34Sopenharmony_ci return -EIO; 125c72fcc34Sopenharmony_ci 126c72fcc34Sopenharmony_ci return 0; 127c72fcc34Sopenharmony_ci} 128c72fcc34Sopenharmony_ci 129c72fcc34Sopenharmony_ci// To avoid blocking execution at system call iteration after receiving UNIX 130c72fcc34Sopenharmony_ci// signals. 131c72fcc34Sopenharmony_cistatic int set_nonblock_flag(int fd) 132c72fcc34Sopenharmony_ci{ 133c72fcc34Sopenharmony_ci int flags; 134c72fcc34Sopenharmony_ci 135c72fcc34Sopenharmony_ci flags = fcntl(fd, F_GETFL); 136c72fcc34Sopenharmony_ci if (flags < 0) 137c72fcc34Sopenharmony_ci return -errno; 138c72fcc34Sopenharmony_ci 139c72fcc34Sopenharmony_ci flags |= O_NONBLOCK; 140c72fcc34Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) 141c72fcc34Sopenharmony_ci return -errno; 142c72fcc34Sopenharmony_ci 143c72fcc34Sopenharmony_ci return 0; 144c72fcc34Sopenharmony_ci} 145c72fcc34Sopenharmony_ci 146c72fcc34Sopenharmony_ciint container_parser_init(struct container_context *cntr, int fd, 147c72fcc34Sopenharmony_ci unsigned int verbose) 148c72fcc34Sopenharmony_ci{ 149c72fcc34Sopenharmony_ci const struct container_parser *parsers[] = { 150c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_RIFF_WAVE] = &container_parser_riff_wave, 151c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_AU] = &container_parser_au, 152c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_VOC] = &container_parser_voc, 153c72fcc34Sopenharmony_ci }; 154c72fcc34Sopenharmony_ci const struct container_parser *parser; 155c72fcc34Sopenharmony_ci unsigned int size; 156c72fcc34Sopenharmony_ci int i; 157c72fcc34Sopenharmony_ci int err; 158c72fcc34Sopenharmony_ci 159c72fcc34Sopenharmony_ci assert(cntr); 160c72fcc34Sopenharmony_ci assert(fd >= 0); 161c72fcc34Sopenharmony_ci 162c72fcc34Sopenharmony_ci // Detect forgotten to destruct. 163c72fcc34Sopenharmony_ci assert(cntr->fd == 0); 164c72fcc34Sopenharmony_ci assert(cntr->private_data == NULL); 165c72fcc34Sopenharmony_ci 166c72fcc34Sopenharmony_ci memset(cntr, 0, sizeof(*cntr)); 167c72fcc34Sopenharmony_ci 168c72fcc34Sopenharmony_ci cntr->fd = fd; 169c72fcc34Sopenharmony_ci 170c72fcc34Sopenharmony_ci cntr->stdio = (cntr->fd == fileno(stdin)); 171c72fcc34Sopenharmony_ci if (cntr->stdio) { 172c72fcc34Sopenharmony_ci if (isatty(cntr->fd)) { 173c72fcc34Sopenharmony_ci fprintf(stderr, 174c72fcc34Sopenharmony_ci "A terminal is referred for standard input. " 175c72fcc34Sopenharmony_ci "Output from any process or shell redirection " 176c72fcc34Sopenharmony_ci "should be referred instead.\n"); 177c72fcc34Sopenharmony_ci return -EIO; 178c72fcc34Sopenharmony_ci } 179c72fcc34Sopenharmony_ci } 180c72fcc34Sopenharmony_ci 181c72fcc34Sopenharmony_ci err = set_nonblock_flag(cntr->fd); 182c72fcc34Sopenharmony_ci if (err < 0) 183c72fcc34Sopenharmony_ci return err; 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_ci // 4 bytes are enough to detect supported containers. 186c72fcc34Sopenharmony_ci err = container_recursive_read(cntr, cntr->magic, sizeof(cntr->magic)); 187c72fcc34Sopenharmony_ci if (err < 0) 188c72fcc34Sopenharmony_ci return err; 189c72fcc34Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(parsers); ++i) { 190c72fcc34Sopenharmony_ci parser = parsers[i]; 191c72fcc34Sopenharmony_ci size = strlen(parser->magic); 192c72fcc34Sopenharmony_ci if (size > 4) 193c72fcc34Sopenharmony_ci size = 4; 194c72fcc34Sopenharmony_ci if (!strncmp(cntr->magic, parser->magic, size)) 195c72fcc34Sopenharmony_ci break; 196c72fcc34Sopenharmony_ci } 197c72fcc34Sopenharmony_ci 198c72fcc34Sopenharmony_ci // Don't forget that the first 4 bytes were already read for magic 199c72fcc34Sopenharmony_ci // bytes. 200c72fcc34Sopenharmony_ci cntr->magic_handled = false; 201c72fcc34Sopenharmony_ci 202c72fcc34Sopenharmony_ci // Unless detected, use raw container. 203c72fcc34Sopenharmony_ci if (i == ARRAY_SIZE(parsers)) 204c72fcc34Sopenharmony_ci parser = &container_parser_raw; 205c72fcc34Sopenharmony_ci 206c72fcc34Sopenharmony_ci // Allocate private data for the parser. 207c72fcc34Sopenharmony_ci if (parser->private_size > 0) { 208c72fcc34Sopenharmony_ci cntr->private_data = malloc(parser->private_size); 209c72fcc34Sopenharmony_ci if (cntr->private_data == NULL) 210c72fcc34Sopenharmony_ci return -ENOMEM; 211c72fcc34Sopenharmony_ci memset(cntr->private_data, 0, parser->private_size); 212c72fcc34Sopenharmony_ci } 213c72fcc34Sopenharmony_ci 214c72fcc34Sopenharmony_ci cntr->type = CONTAINER_TYPE_PARSER; 215c72fcc34Sopenharmony_ci cntr->process_bytes = container_recursive_read; 216c72fcc34Sopenharmony_ci cntr->format = parser->format; 217c72fcc34Sopenharmony_ci cntr->ops = &parser->ops; 218c72fcc34Sopenharmony_ci cntr->max_size = parser->max_size; 219c72fcc34Sopenharmony_ci cntr->verbose = verbose; 220c72fcc34Sopenharmony_ci 221c72fcc34Sopenharmony_ci return 0; 222c72fcc34Sopenharmony_ci} 223c72fcc34Sopenharmony_ci 224c72fcc34Sopenharmony_ciint container_builder_init(struct container_context *cntr, int fd, 225c72fcc34Sopenharmony_ci enum container_format format, unsigned int verbose) 226c72fcc34Sopenharmony_ci{ 227c72fcc34Sopenharmony_ci const struct container_builder *builders[] = { 228c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_RIFF_WAVE] = &container_builder_riff_wave, 229c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_AU] = &container_builder_au, 230c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_VOC] = &container_builder_voc, 231c72fcc34Sopenharmony_ci [CONTAINER_FORMAT_RAW] = &container_builder_raw, 232c72fcc34Sopenharmony_ci }; 233c72fcc34Sopenharmony_ci const struct container_builder *builder; 234c72fcc34Sopenharmony_ci int err; 235c72fcc34Sopenharmony_ci 236c72fcc34Sopenharmony_ci assert(cntr); 237c72fcc34Sopenharmony_ci assert(fd >= 0); 238c72fcc34Sopenharmony_ci 239c72fcc34Sopenharmony_ci // Detect forgotten to destruct. 240c72fcc34Sopenharmony_ci assert(cntr->fd == 0); 241c72fcc34Sopenharmony_ci assert(cntr->private_data == NULL); 242c72fcc34Sopenharmony_ci 243c72fcc34Sopenharmony_ci memset(cntr, 0, sizeof(*cntr)); 244c72fcc34Sopenharmony_ci 245c72fcc34Sopenharmony_ci cntr->fd = fd; 246c72fcc34Sopenharmony_ci 247c72fcc34Sopenharmony_ci cntr->stdio = (cntr->fd == fileno(stdout)); 248c72fcc34Sopenharmony_ci if (cntr->stdio) { 249c72fcc34Sopenharmony_ci if (isatty(cntr->fd)) { 250c72fcc34Sopenharmony_ci fprintf(stderr, 251c72fcc34Sopenharmony_ci "A terminal is referred for standard output. " 252c72fcc34Sopenharmony_ci "Input to any process or shell redirection " 253c72fcc34Sopenharmony_ci "should be referred instead.\n"); 254c72fcc34Sopenharmony_ci return -EIO; 255c72fcc34Sopenharmony_ci } 256c72fcc34Sopenharmony_ci } 257c72fcc34Sopenharmony_ci 258c72fcc34Sopenharmony_ci err = set_nonblock_flag(cntr->fd); 259c72fcc34Sopenharmony_ci if (err < 0) 260c72fcc34Sopenharmony_ci return err; 261c72fcc34Sopenharmony_ci 262c72fcc34Sopenharmony_ci builder = builders[format]; 263c72fcc34Sopenharmony_ci 264c72fcc34Sopenharmony_ci // Allocate private data for the builder. 265c72fcc34Sopenharmony_ci if (builder->private_size > 0) { 266c72fcc34Sopenharmony_ci cntr->private_data = malloc(builder->private_size); 267c72fcc34Sopenharmony_ci if (cntr->private_data == NULL) 268c72fcc34Sopenharmony_ci return -ENOMEM; 269c72fcc34Sopenharmony_ci memset(cntr->private_data, 0, builder->private_size); 270c72fcc34Sopenharmony_ci } 271c72fcc34Sopenharmony_ci 272c72fcc34Sopenharmony_ci cntr->type = CONTAINER_TYPE_BUILDER; 273c72fcc34Sopenharmony_ci cntr->process_bytes = container_recursive_write; 274c72fcc34Sopenharmony_ci cntr->format = builder->format; 275c72fcc34Sopenharmony_ci cntr->ops = &builder->ops; 276c72fcc34Sopenharmony_ci cntr->max_size = builder->max_size; 277c72fcc34Sopenharmony_ci cntr->verbose = verbose; 278c72fcc34Sopenharmony_ci 279c72fcc34Sopenharmony_ci return 0; 280c72fcc34Sopenharmony_ci} 281c72fcc34Sopenharmony_ci 282c72fcc34Sopenharmony_ciint container_context_pre_process(struct container_context *cntr, 283c72fcc34Sopenharmony_ci snd_pcm_format_t *format, 284c72fcc34Sopenharmony_ci unsigned int *samples_per_frame, 285c72fcc34Sopenharmony_ci unsigned int *frames_per_second, 286c72fcc34Sopenharmony_ci uint64_t *frame_count) 287c72fcc34Sopenharmony_ci{ 288c72fcc34Sopenharmony_ci uint64_t byte_count = 0; 289c72fcc34Sopenharmony_ci unsigned int bytes_per_frame; 290c72fcc34Sopenharmony_ci int err; 291c72fcc34Sopenharmony_ci 292c72fcc34Sopenharmony_ci assert(cntr); 293c72fcc34Sopenharmony_ci assert(format); 294c72fcc34Sopenharmony_ci assert(samples_per_frame); 295c72fcc34Sopenharmony_ci assert(frames_per_second); 296c72fcc34Sopenharmony_ci assert(frame_count); 297c72fcc34Sopenharmony_ci 298c72fcc34Sopenharmony_ci if (cntr->type == CONTAINER_TYPE_BUILDER) 299c72fcc34Sopenharmony_ci byte_count = cntr->max_size; 300c72fcc34Sopenharmony_ci 301c72fcc34Sopenharmony_ci if (cntr->ops->pre_process) { 302c72fcc34Sopenharmony_ci err = cntr->ops->pre_process(cntr, format, samples_per_frame, 303c72fcc34Sopenharmony_ci frames_per_second, &byte_count); 304c72fcc34Sopenharmony_ci if (err < 0) 305c72fcc34Sopenharmony_ci return err; 306c72fcc34Sopenharmony_ci if (cntr->eof) 307c72fcc34Sopenharmony_ci return 0; 308c72fcc34Sopenharmony_ci } 309c72fcc34Sopenharmony_ci 310c72fcc34Sopenharmony_ci if (cntr->format == CONTAINER_FORMAT_RAW) { 311c72fcc34Sopenharmony_ci if (*format == SND_PCM_FORMAT_UNKNOWN || 312c72fcc34Sopenharmony_ci *samples_per_frame == 0 || *frames_per_second == 0) { 313c72fcc34Sopenharmony_ci fprintf(stderr, 314c72fcc34Sopenharmony_ci "Any file format is not detected. Need to " 315c72fcc34Sopenharmony_ci "indicate all of sample format, channels and " 316c72fcc34Sopenharmony_ci "rate explicitly.\n"); 317c72fcc34Sopenharmony_ci return -EINVAL; 318c72fcc34Sopenharmony_ci } 319c72fcc34Sopenharmony_ci } 320c72fcc34Sopenharmony_ci assert(*format >= SND_PCM_FORMAT_S8); 321c72fcc34Sopenharmony_ci assert(*format <= SND_PCM_FORMAT_LAST); 322c72fcc34Sopenharmony_ci assert(*samples_per_frame > 0); 323c72fcc34Sopenharmony_ci assert(*frames_per_second > 0); 324c72fcc34Sopenharmony_ci assert(byte_count > 0); 325c72fcc34Sopenharmony_ci 326c72fcc34Sopenharmony_ci cntr->bytes_per_sample = snd_pcm_format_physical_width(*format) / 8; 327c72fcc34Sopenharmony_ci cntr->samples_per_frame = *samples_per_frame; 328c72fcc34Sopenharmony_ci cntr->frames_per_second = *frames_per_second; 329c72fcc34Sopenharmony_ci 330c72fcc34Sopenharmony_ci bytes_per_frame = cntr->bytes_per_sample * *samples_per_frame; 331c72fcc34Sopenharmony_ci *frame_count = byte_count / bytes_per_frame; 332c72fcc34Sopenharmony_ci cntr->max_size -= cntr->max_size / bytes_per_frame; 333c72fcc34Sopenharmony_ci 334c72fcc34Sopenharmony_ci if (cntr->verbose > 0) { 335c72fcc34Sopenharmony_ci fprintf(stderr, "Container: %s\n", 336c72fcc34Sopenharmony_ci cntr_type_labels[cntr->type]); 337c72fcc34Sopenharmony_ci fprintf(stderr, " format: %s\n", 338c72fcc34Sopenharmony_ci cntr_format_labels[cntr->format]); 339c72fcc34Sopenharmony_ci fprintf(stderr, " sample format: %s\n", 340c72fcc34Sopenharmony_ci snd_pcm_format_name(*format)); 341c72fcc34Sopenharmony_ci fprintf(stderr, " bytes/sample: %u\n", 342c72fcc34Sopenharmony_ci cntr->bytes_per_sample); 343c72fcc34Sopenharmony_ci fprintf(stderr, " samples/frame: %u\n", 344c72fcc34Sopenharmony_ci cntr->samples_per_frame); 345c72fcc34Sopenharmony_ci fprintf(stderr, " frames/second: %u\n", 346c72fcc34Sopenharmony_ci cntr->frames_per_second); 347c72fcc34Sopenharmony_ci if (cntr->type == CONTAINER_TYPE_PARSER) { 348c72fcc34Sopenharmony_ci fprintf(stderr, " frames: %" PRIu64 "\n", 349c72fcc34Sopenharmony_ci *frame_count); 350c72fcc34Sopenharmony_ci } else { 351c72fcc34Sopenharmony_ci fprintf(stderr, " max frames: %" PRIu64 "\n", 352c72fcc34Sopenharmony_ci *frame_count); 353c72fcc34Sopenharmony_ci } 354c72fcc34Sopenharmony_ci } 355c72fcc34Sopenharmony_ci 356c72fcc34Sopenharmony_ci return 0; 357c72fcc34Sopenharmony_ci} 358c72fcc34Sopenharmony_ci 359c72fcc34Sopenharmony_ciint container_context_process_frames(struct container_context *cntr, 360c72fcc34Sopenharmony_ci void *frame_buffer, 361c72fcc34Sopenharmony_ci unsigned int *frame_count) 362c72fcc34Sopenharmony_ci{ 363c72fcc34Sopenharmony_ci char *buf = frame_buffer; 364c72fcc34Sopenharmony_ci unsigned int bytes_per_frame; 365c72fcc34Sopenharmony_ci unsigned int byte_count; 366c72fcc34Sopenharmony_ci unsigned int target_byte_count; 367c72fcc34Sopenharmony_ci int err; 368c72fcc34Sopenharmony_ci 369c72fcc34Sopenharmony_ci assert(cntr); 370c72fcc34Sopenharmony_ci assert(!cntr->eof); 371c72fcc34Sopenharmony_ci assert(frame_buffer); 372c72fcc34Sopenharmony_ci assert(frame_count); 373c72fcc34Sopenharmony_ci 374c72fcc34Sopenharmony_ci bytes_per_frame = cntr->bytes_per_sample * cntr->samples_per_frame; 375c72fcc34Sopenharmony_ci target_byte_count = *frame_count * bytes_per_frame; 376c72fcc34Sopenharmony_ci 377c72fcc34Sopenharmony_ci // A parser of cotainers already read first 4 bytes to detect format 378c72fcc34Sopenharmony_ci // of container, however they includes PCM frames when any format was 379c72fcc34Sopenharmony_ci // undetected. Surely to write out them. 380c72fcc34Sopenharmony_ci byte_count = target_byte_count; 381c72fcc34Sopenharmony_ci if (cntr->format == CONTAINER_FORMAT_RAW && 382c72fcc34Sopenharmony_ci cntr->type == CONTAINER_TYPE_PARSER && !cntr->magic_handled) { 383c72fcc34Sopenharmony_ci memcpy(buf, cntr->magic, sizeof(cntr->magic)); 384c72fcc34Sopenharmony_ci buf += sizeof(cntr->magic); 385c72fcc34Sopenharmony_ci byte_count -= sizeof(cntr->magic); 386c72fcc34Sopenharmony_ci cntr->magic_handled = true; 387c72fcc34Sopenharmony_ci } 388c72fcc34Sopenharmony_ci 389c72fcc34Sopenharmony_ci // Each container has limitation for its volume for sample data. 390c72fcc34Sopenharmony_ci if (cntr->handled_byte_count > cntr->max_size - byte_count) 391c72fcc34Sopenharmony_ci byte_count = cntr->max_size - cntr->handled_byte_count; 392c72fcc34Sopenharmony_ci 393c72fcc34Sopenharmony_ci // All of supported containers include interleaved PCM frames. 394c72fcc34Sopenharmony_ci // TODO: process frames for truncate case. 395c72fcc34Sopenharmony_ci err = cntr->process_bytes(cntr, buf, byte_count); 396c72fcc34Sopenharmony_ci if (err < 0) { 397c72fcc34Sopenharmony_ci *frame_count = 0; 398c72fcc34Sopenharmony_ci return err; 399c72fcc34Sopenharmony_ci } 400c72fcc34Sopenharmony_ci 401c72fcc34Sopenharmony_ci cntr->handled_byte_count += target_byte_count; 402c72fcc34Sopenharmony_ci if (cntr->handled_byte_count == cntr->max_size) 403c72fcc34Sopenharmony_ci cntr->eof = true; 404c72fcc34Sopenharmony_ci 405c72fcc34Sopenharmony_ci *frame_count = target_byte_count / bytes_per_frame; 406c72fcc34Sopenharmony_ci 407c72fcc34Sopenharmony_ci return 0; 408c72fcc34Sopenharmony_ci} 409c72fcc34Sopenharmony_ci 410c72fcc34Sopenharmony_ciint container_context_post_process(struct container_context *cntr, 411c72fcc34Sopenharmony_ci uint64_t *frame_count) 412c72fcc34Sopenharmony_ci{ 413c72fcc34Sopenharmony_ci int err = 0; 414c72fcc34Sopenharmony_ci 415c72fcc34Sopenharmony_ci assert(cntr); 416c72fcc34Sopenharmony_ci assert(frame_count); 417c72fcc34Sopenharmony_ci 418c72fcc34Sopenharmony_ci if (cntr->verbose && cntr->handled_byte_count > 0) { 419c72fcc34Sopenharmony_ci fprintf(stderr, " Handled bytes: %" PRIu64 "\n", 420c72fcc34Sopenharmony_ci cntr->handled_byte_count); 421c72fcc34Sopenharmony_ci } 422c72fcc34Sopenharmony_ci 423c72fcc34Sopenharmony_ci // NOTE* we cannot seek when using standard input/output. 424c72fcc34Sopenharmony_ci if (!cntr->stdio && cntr->ops && cntr->ops->post_process) { 425c72fcc34Sopenharmony_ci // Usually, need to write out processed bytes in container 426c72fcc34Sopenharmony_ci // header even it this program is interrupted. 427c72fcc34Sopenharmony_ci cntr->interrupted = false; 428c72fcc34Sopenharmony_ci 429c72fcc34Sopenharmony_ci err = cntr->ops->post_process(cntr, cntr->handled_byte_count); 430c72fcc34Sopenharmony_ci } 431c72fcc34Sopenharmony_ci 432c72fcc34Sopenharmony_ci // Ensure to perform write-back from disk cache. 433c72fcc34Sopenharmony_ci if (cntr->type == CONTAINER_TYPE_BUILDER) 434c72fcc34Sopenharmony_ci fsync(cntr->fd); 435c72fcc34Sopenharmony_ci 436c72fcc34Sopenharmony_ci if (err < 0) 437c72fcc34Sopenharmony_ci return err; 438c72fcc34Sopenharmony_ci 439c72fcc34Sopenharmony_ci if (cntr->bytes_per_sample == 0 || cntr->samples_per_frame == 0) { 440c72fcc34Sopenharmony_ci *frame_count = 0; 441c72fcc34Sopenharmony_ci } else { 442c72fcc34Sopenharmony_ci *frame_count = cntr->handled_byte_count / 443c72fcc34Sopenharmony_ci cntr->bytes_per_sample / 444c72fcc34Sopenharmony_ci cntr->samples_per_frame; 445c72fcc34Sopenharmony_ci } 446c72fcc34Sopenharmony_ci 447c72fcc34Sopenharmony_ci return 0; 448c72fcc34Sopenharmony_ci} 449c72fcc34Sopenharmony_ci 450c72fcc34Sopenharmony_civoid container_context_destroy(struct container_context *cntr) 451c72fcc34Sopenharmony_ci{ 452c72fcc34Sopenharmony_ci assert(cntr); 453c72fcc34Sopenharmony_ci 454c72fcc34Sopenharmony_ci if (cntr->private_data) 455c72fcc34Sopenharmony_ci free(cntr->private_data); 456c72fcc34Sopenharmony_ci 457c72fcc34Sopenharmony_ci cntr->fd = 0; 458c72fcc34Sopenharmony_ci cntr->private_data = NULL; 459c72fcc34Sopenharmony_ci} 460