diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/avilib/wavlib.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/avilib/wavlib.c | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/avilib/wavlib.c b/debian/transcode/transcode-1.1.7/avilib/wavlib.c new file mode 100644 index 00000000..b5b462b0 --- /dev/null +++ b/debian/transcode/transcode-1.1.7/avilib/wavlib.c @@ -0,0 +1,577 @@ +/* + * wavlib.c - simple WAV I/O library interface + * Copyright (C) 2006-2010 Francesco Romani <fromani at gmail dot com> + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "wavlib.h" +#include "platform.h" + +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +/************************************************************************* + * utilties * + *************************************************************************/ + +#define WAV_BUF_SIZE (1024) + +#if (!defined HAVE_BYTESWAP && defined WAV_BIG_ENDIAN) + +static uint16_t bswap_16(uint16_t x) +{ + return (((x & 0xff00) >> 8) | ((x & 0x00ff) << 8)); +} + +static uint32_t bswap_32(uint32_t x) +{ + return (((x & 0xff000000UL) >> 24) | + ((x & 0x00ff0000UL) >> 8) | + ((x & 0x0000ff00UL) << 8) | + ((x & 0x000000ffUL) << 24)); +} + +static uint64_t bswap_64(uint64_t x) +{ + return (((x & 0xff00000000000000ULL) >> 56) | + ((x & 0x00ff000000000000ULL) >> 40) | + ((x & 0x0000ff0000000000ULL) >> 24) | + ((x & 0x000000ff00000000ULL) >> 8) | + ((x & 0x00000000ff000000ULL) << 8) | + ((x & 0x0000000000ff0000ULL) << 24) | + ((x & 0x000000000000ff00ULL) << 40) | + ((x & 0x00000000000000ffULL) << 56)); +} +#endif + +#if (!defined WAV_BIG_ENDIAN && !defined WAV_LITTLE_ENDIAN) +#error "you must define either LITTLE_ENDIAN or BIG_ENDIAN" +#endif + +#if (defined WAV_BIG_ENDIAN && defined WAV_LITTLE_ENDIAN) +#error "you CAN'T define BOTH LITTLE_ENDIAN and BIG_ENDIAN" +#endif + +#if defined WAV_BIG_ENDIAN +#define htol_16(x) bswap_16(x) +#define htol_32(x) bswap_32(x) +#define htol_64(x) bswap_64(x) + +#elif defined WAV_LITTLE_ENDIAN + +#define htol_16(x) (x) +#define htol_32(x) (x) +#define htol_64(x) (x) + +#endif + +/* often used out-of-order */ +#define make_wav_get_bits(s) \ +static inline uint##s##_t wav_get_bits##s(uint8_t *d) \ +{ \ + return htol_##s(*((uint##s##_t*)d)); \ +} + +/* often used sequentially */ +#define make_wav_put_bits(s) \ +static inline uint8_t *wav_put_bits##s(uint8_t *d, uint##s##_t u) \ +{ \ + *((uint##s##_t*)d) = htol_##s(u); \ + return (d + (s / 8)); \ +} + +make_wav_get_bits(16) +make_wav_get_bits(32) +make_wav_get_bits(64) + +make_wav_put_bits(16) +make_wav_put_bits(32) +make_wav_put_bits(64) + +static inline uint32_t make_tag(uint8_t a, uint8_t b, uint8_t c, uint8_t d) +{ + return (a | (b << 8) | (c << 16) | (d << 24)); +} + +/************************************************************************* + * header data * + *************************************************************************/ + +/* + * WAVE header: + * + * TAG: 'RIFF' 4 bytes + * LENGTH: 4 bytes + * TAG: 'WAVE' 4 bytes + * + * TAG: 'fmt ' 4 bytes + * LENGTH: 4 bytes + * + * + + * FORMAT: 2 bytes | + * CHANNELS: 2 bytes | + * SAMPLES: 4 bytes | simple WAV format: + * AVGBYTES: 4 bytes | 16 byte + * BLKALIGN: 2 bytes | + * BITS: 2 bytes | + * + + * + * TAG: 'data' 4 bytes + * LENGTH: 4 bytes + * + * ---------------------------- + * TOTAL wav header: 44 bytes + */ + +#define WAV_HEADER_LEN (44) +#define WAV_FORMAT_LEN (16) + +#define PCM_ID (0x1) + +/************************************************************************* + * core data/routines * + *************************************************************************/ + +#define WAV_SET_ERROR(errp, code) \ + if (errp != NULL) { \ + *errp = code; \ + } + +struct wav_ { + int fd; + + int header_done; + int close_fd; + int has_pipe; + + WAVMode mode; + WAVError error; + + uint32_t len; + + uint32_t bitrate; + uint16_t bits; + uint16_t channels; + uint32_t rate; + + uint16_t block_align; +}; + +const char *wav_strerror(WAVError err) +{ + const char *s = NULL; + + switch (err) { + case WAV_SUCCESS: + s = "no error"; + break; + case WAV_NO_MEM: + s = "can't acquire the needed amount of memory"; + break; + case WAV_IO_ERROR: + s = "error while performing I/O operation"; + break; + case WAV_BAD_FORMAT: + s = "incorrect/unrecognized WAV data"; + break; + case WAV_BAD_PARAM: + s = "bad/unknown parameter for this operation"; + break; + case WAV_UNSUPPORTED: + s = "not yet supported by wavlib"; + break; + default: + s = NULL; + break; + } + return s; +} + +static int wav_parse_header(WAV handle, WAVError *err) +{ + uint8_t hdr[WAV_HEADER_LEN]; + ssize_t r = 0; + uint16_t wav_fmt = 0; + uint32_t fmt_len = 0; + + if (!handle || handle->fd == -1 || !(handle->mode & WAV_READ)) { + return -1; + } + + r = plat_read(handle->fd, hdr, WAV_HEADER_LEN); + if (r != WAV_HEADER_LEN) { + WAV_SET_ERROR(err, WAV_BAD_FORMAT); + goto bad_wav; + } + if ((wav_get_bits32(hdr) != make_tag('R', 'I', 'F', 'F')) + || (wav_get_bits32(hdr + 8) != make_tag('W', 'A', 'V', 'E')) + || (wav_get_bits32(hdr + 12) != make_tag('f', 'm', 't', ' '))) { + WAV_SET_ERROR(err, WAV_BAD_FORMAT); + goto bad_wav; + } + + fmt_len = wav_get_bits32(hdr + 16); + wav_fmt = wav_get_bits16(hdr + 20); + if (fmt_len != WAV_FORMAT_LEN || wav_fmt != PCM_ID) { + WAV_SET_ERROR(err, WAV_UNSUPPORTED); + goto bad_wav; + } + + handle->len = wav_get_bits32(hdr + 4); + handle->channels = wav_get_bits16(hdr + 22); + handle->rate = wav_get_bits32(hdr + 24); + handle->bitrate = (wav_get_bits32(hdr + 28) * 8) / 1000; + handle->block_align = wav_get_bits16(hdr + 32); + handle->bits = wav_get_bits16(hdr + 34); + /* skip 'data' tag (4 bytes) */ + handle->len = wav_get_bits32(hdr + 40); + + return 0; + +bad_wav: + lseek(handle->fd, 0, SEEK_SET); + return 1; +} + +int wav_write_header(WAV handle, int force) +{ + uint8_t hdr[WAV_HEADER_LEN]; + uint8_t *ph = hdr; + off_t pos = 0, ret = 0; + ssize_t w = 0; + + if (!handle) { + return -1; + } + if (!force && handle->header_done) { + return 0; + } + if (handle->bits != 0 + && (handle->bits != 8 && handle->bits != 16)) { + /* bits == 0 -> not specified (so it's good) */ + WAV_SET_ERROR(&(handle->error), WAV_UNSUPPORTED); + return -1; + } + + if (!handle->has_pipe) { + pos = lseek(handle->fd, 0, SEEK_CUR); + ret = lseek(handle->fd, 0, SEEK_SET); + if (ret == (off_t)-1) { + return 1; + } + } + + ph = wav_put_bits32(ph, make_tag('R', 'I', 'F', 'F')); + ph = wav_put_bits32(ph, handle->len + WAV_HEADER_LEN - 8); + ph = wav_put_bits32(ph, make_tag('W', 'A', 'V', 'E')); + + ph = wav_put_bits32(ph, make_tag('f', 'm', 't', ' ')); + ph = wav_put_bits32(ph, WAV_FORMAT_LEN); + + /* format */ + ph = wav_put_bits16(ph, PCM_ID); + /* wave format, only plain PCM supported, yet */ + ph = wav_put_bits16(ph, handle->channels); + /* number of channels */ + ph = wav_put_bits32(ph, handle->rate); + /* sample rate */ + ph = wav_put_bits32(ph, (handle->bitrate * 1000)/8); + /* average bytes per second (aka bitrate) */ + ph = wav_put_bits16(ph, ((handle->channels * handle->bits) / 8)); + /* block alignment */ + ph = wav_put_bits16(ph, handle->bits); + /* bits for sample */ + + ph = wav_put_bits32(ph, make_tag('d', 'a', 't', 'a')); + ph = wav_put_bits32(ph, handle->len); + + w = plat_write(handle->fd, hdr, WAV_HEADER_LEN); + + if (!handle->has_pipe) { + ret = lseek(handle->fd, pos, SEEK_CUR); + if (ret == (off_t)-1) { + return 1; + } + } + + if (w != WAV_HEADER_LEN) { + return 2; + } + handle->header_done = 1; + return 0; +} + +WAV wav_open(const char *filename, WAVMode mode, WAVError *err) +{ + int oflags = (mode & WAV_READ) ?O_RDONLY :O_TRUNC|O_CREAT|O_WRONLY; + int fd = -1; + WAV wav = NULL; + + if (!filename || !strlen(filename)) { + WAV_SET_ERROR(err, WAV_BAD_PARAM); + } else { + fd = plat_open(filename, oflags, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + wav = wav_fdopen(fd, mode, err); + if (!wav) { + plat_close(fd); + } else { + wav->close_fd = 1; + } + } + return wav; +} + +#define DEL_WAV(wav) do { \ + plat_free((wav)); \ + (wav) = NULL; \ +} while (0) + +WAV wav_fdopen(int fd, WAVMode mode, WAVError *err) +{ + WAV wav = plat_zalloc(sizeof(struct wav_)); + + if (!wav) { + WAV_SET_ERROR(err, WAV_NO_MEM); + } else { + wav->fd = fd; + wav->mode = mode; + wav->close_fd = 0; + wav->has_pipe = (mode & WAV_PIPE) ?1 :0; + + if (mode & WAV_READ) { + if (0 != wav_parse_header(wav, err)) { + DEL_WAV(wav); + } else { + wav->header_done = 1; /* skip write_header */ + } + } else if (mode & WAV_WRITE) { + /* reserve space for header by writing a fake one */ + if (!wav->has_pipe && 0 != wav_write_header(wav, 1)) { + WAV_SET_ERROR(err, wav->error); + /* only I/O error */ + DEL_WAV(wav); + } + } else { + WAV_SET_ERROR(err, WAV_BAD_PARAM); + DEL_WAV(wav); + } + } + return wav; +} + + +#define RETURN_IF_IOERROR(err) \ + if (err != 0) { \ + WAV_SET_ERROR(&(handle->error), WAV_IO_ERROR); \ + return -1; \ + } + +int wav_close(WAV handle) +{ + int ret = 0; + + if (!handle) { + return -1; + } + + if (!handle->has_pipe && handle->mode & WAV_WRITE) { + ret = wav_write_header(handle, 1); + RETURN_IF_IOERROR(ret); + } + + if (handle->close_fd) { + ret = plat_close(handle->fd); + RETURN_IF_IOERROR(ret); + } + plat_free(handle); + + return 0; +} + +#undef RETURN_IF_IOERROR + +uint32_t wav_chunk_size(WAV handle, double fps) +{ + uint32_t size = 0; + double fch; + + if (!handle || !fps) { + return -1; + } + + fch = handle->rate / fps; + + /* bytes per audio frame */ + size = (int)(fch * (handle->bits / 8) * handle->channels); + size = (size>>2)<<2; /* XXX */ + + return 0; +} + +WAVError wav_last_error(WAV handle) +{ + return (handle) ?(handle->error) :WAV_BAD_PARAM; +} + +uint32_t wav_get_bitrate(WAV handle) +{ + return (handle) ?(handle->bitrate) :0; +} + +uint16_t wav_get_rate(WAV handle) +{ + return (handle) ?(handle->rate) :0; +} + +uint8_t wav_get_channels(WAV handle) +{ + return (handle) ?(handle->channels) :0; +} + +uint8_t wav_get_bits(WAV handle) +{ + return (handle) ?(handle->bits) :0; +} + +void wav_set_rate(WAV handle, uint16_t rate) +{ + if (handle && handle->mode & WAV_WRITE) { + handle->rate = rate; + } +} + +void wav_set_channels(WAV handle, uint8_t channels) +{ + if (handle && handle->mode & WAV_WRITE) { + handle->channels = channels; + } +} + +void wav_set_bits(WAV handle, uint8_t bits) +{ + if (handle && handle->mode & WAV_WRITE) { + handle->bits = bits; + } +} + +void wav_set_bitrate(WAV handle, uint32_t bitrate) +{ + if (handle && handle->mode & WAV_WRITE) { + handle->bitrate = bitrate; + } +} + +#ifdef WAV_BIG_ENDIAN + +/* assume dlen % 2 == 0 */ +static void bswap_buffer(void *data, size_t bytes) +{ + size_t i = 0; + uint16_t *ptr = data; + + for (ptr = data, i = 0; i < bytes; ptr++, i += 2) { + *ptr = bswap_16(*ptr); + } +} + +#define SWAP_WRITE_CHUNK(data, len) do { \ + memcpy(conv_buf, (data), (len)); \ + bswap_buffer(conv_buf, (len)); \ + ret = plat_write(fd, conv_buf, (len)); \ +} while (0) + +static ssize_t wav_bswap_fdwrite(int fd, const uint8_t *buf, size_t len) +{ + uint8_t conv_buf[WAV_BUF_SIZE]; + size_t blocks = len / WAV_BUF_SIZE, rest = len % WAV_BUF_SIZE, i = 0; + ssize_t ret = 0, tot = 0; + + for (i = 0; i < blocks; i++) { + SWAP_WRITE_CHUNK(buf + (i * WAV_BUF_SIZE), WAV_BUF_SIZE); + if (ret != WAV_BUF_SIZE) { + break; + } + tot += ret; + } + + SWAP_WRITE_CHUNK(buf + (i * WAV_BUF_SIZE), rest); + return tot + ret; +} + +#undef SWAP_WRITE_CHUNK + +#endif /* WAV_BIG_ENDIAN */ + +ssize_t wav_read_data(WAV handle, uint8_t *buffer, size_t bufsize) +{ + ssize_t r = 0; + + if (!handle) { + return -1; + } + if (!buffer || bufsize < 0) { + WAV_SET_ERROR(&(handle->error), WAV_BAD_PARAM); + return -1; + } + if (!(handle->mode & WAV_READ) || (bufsize % 2 != 0)) { + WAV_SET_ERROR(&(handle->error), WAV_UNSUPPORTED); + return -1; + } + r = plat_read(handle->fd, buffer, bufsize); + +#ifdef WAV_BIG_ENDIAN + bswap_buffer(buffer, r); +#endif + return r; +} + +ssize_t wav_write_data(WAV handle, const uint8_t *buffer, size_t bufsize) +{ + ssize_t w = 0; + + if (!handle) { + return -1; + } + if (!buffer || bufsize < 0) { + WAV_SET_ERROR(&(handle->error), WAV_BAD_PARAM); + return -1; + } + if (!(handle->mode & WAV_WRITE) || (bufsize % 2 != 0)) { + WAV_SET_ERROR(&(handle->error), WAV_UNSUPPORTED); + return -1; + } + if (wav_write_header(handle, 0) != 0) { + return -1; + } +#ifdef WAV_BIG_ENDIAN + w = wav_bswap_fdwrite(handle->fd, buffer, bufsize); +#else + w = plat_write(handle->fd, buffer, bufsize); +#endif + if (w == bufsize) { + handle->len += w; + } + return w; +} + |
