summaryrefslogtreecommitdiffstats
path: root/debian/transcode/transcode-1.1.7/avilib/wavlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/transcode/transcode-1.1.7/avilib/wavlib.c')
-rw-r--r--debian/transcode/transcode-1.1.7/avilib/wavlib.c577
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;
+}
+