Chris@0: /* Chris@0: * libmad - MPEG audio decoder library Chris@0: * Copyright (C) 2000-2004 Underbit Technologies, Inc. Chris@0: * Chris@0: * This program is free software; you can redistribute it and/or modify Chris@0: * it under the terms of the GNU General Public License as published by Chris@0: * the Free Software Foundation; either version 2 of the License, or Chris@0: * (at your option) any later version. Chris@0: * Chris@0: * This program is distributed in the hope that it will be useful, Chris@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@0: * GNU General Public License for more details. Chris@0: * Chris@0: * You should have received a copy of the GNU General Public License Chris@0: * along with this program; if not, write to the Free Software Chris@0: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Chris@0: * Chris@0: * $Id: decoder.c,v 1.22 2004/01/23 09:41:32 rob Exp $ Chris@0: */ Chris@0: Chris@0: # ifdef HAVE_CONFIG_H Chris@0: # include "config.h" Chris@0: # endif Chris@0: Chris@0: # include "global.h" Chris@0: Chris@0: # ifdef HAVE_SYS_TYPES_H Chris@0: # include Chris@0: # endif Chris@0: Chris@0: # ifdef HAVE_SYS_WAIT_H Chris@0: # include Chris@0: # endif Chris@0: Chris@0: # ifdef HAVE_UNISTD_H Chris@0: # include Chris@0: # endif Chris@0: Chris@0: # ifdef HAVE_FCNTL_H Chris@0: # include Chris@0: # endif Chris@0: Chris@0: # include Chris@0: Chris@0: # ifdef HAVE_ERRNO_H Chris@0: # include Chris@0: # endif Chris@0: Chris@0: # include "stream.h" Chris@0: # include "frame.h" Chris@0: # include "synth.h" Chris@0: # include "decoder.h" Chris@0: Chris@0: /* Chris@0: * NAME: decoder->init() Chris@0: * DESCRIPTION: initialize a decoder object with callback routines Chris@0: */ Chris@0: void mad_decoder_init(struct mad_decoder *decoder, void *data, Chris@0: enum mad_flow (*input_func)(void *, Chris@0: struct mad_stream *), Chris@0: enum mad_flow (*header_func)(void *, Chris@0: struct mad_header const *), Chris@0: enum mad_flow (*filter_func)(void *, Chris@0: struct mad_stream const *, Chris@0: struct mad_frame *), Chris@0: enum mad_flow (*output_func)(void *, Chris@0: struct mad_header const *, Chris@0: struct mad_pcm *), Chris@0: enum mad_flow (*error_func)(void *, Chris@0: struct mad_stream *, Chris@0: struct mad_frame *), Chris@0: enum mad_flow (*message_func)(void *, Chris@0: void *, unsigned int *)) Chris@0: { Chris@0: decoder->mode = -1; Chris@0: Chris@0: decoder->options = 0; Chris@0: Chris@0: decoder->async.pid = 0; Chris@0: decoder->async.in = -1; Chris@0: decoder->async.out = -1; Chris@0: Chris@0: decoder->sync = 0; Chris@0: Chris@0: decoder->cb_data = data; Chris@0: Chris@0: decoder->input_func = input_func; Chris@0: decoder->header_func = header_func; Chris@0: decoder->filter_func = filter_func; Chris@0: decoder->output_func = output_func; Chris@0: decoder->error_func = error_func; Chris@0: decoder->message_func = message_func; Chris@0: } Chris@0: Chris@0: int mad_decoder_finish(struct mad_decoder *decoder) Chris@0: { Chris@0: # if defined(USE_ASYNC) Chris@0: if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) { Chris@0: pid_t pid; Chris@0: int status; Chris@0: Chris@0: close(decoder->async.in); Chris@0: Chris@0: do Chris@0: pid = waitpid(decoder->async.pid, &status, 0); Chris@0: while (pid == -1 && errno == EINTR); Chris@0: Chris@0: decoder->mode = -1; Chris@0: Chris@0: close(decoder->async.out); Chris@0: Chris@0: decoder->async.pid = 0; Chris@0: decoder->async.in = -1; Chris@0: decoder->async.out = -1; Chris@0: Chris@0: if (pid == -1) Chris@0: return -1; Chris@0: Chris@0: return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0; Chris@0: } Chris@0: # endif Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: # if defined(USE_ASYNC) Chris@0: static Chris@0: enum mad_flow send_io(int fd, void const *data, size_t len) Chris@0: { Chris@0: char const *ptr = data; Chris@0: ssize_t count; Chris@0: Chris@0: while (len) { Chris@0: do Chris@0: count = write(fd, ptr, len); Chris@0: while (count == -1 && errno == EINTR); Chris@0: Chris@0: if (count == -1) Chris@0: return MAD_FLOW_BREAK; Chris@0: Chris@0: len -= count; Chris@0: ptr += count; Chris@0: } Chris@0: Chris@0: return MAD_FLOW_CONTINUE; Chris@0: } Chris@0: Chris@0: static Chris@0: enum mad_flow receive_io(int fd, void *buffer, size_t len) Chris@0: { Chris@0: char *ptr = buffer; Chris@0: ssize_t count; Chris@0: Chris@0: while (len) { Chris@0: do Chris@0: count = read(fd, ptr, len); Chris@0: while (count == -1 && errno == EINTR); Chris@0: Chris@0: if (count == -1) Chris@0: return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK; Chris@0: else if (count == 0) Chris@0: return MAD_FLOW_STOP; Chris@0: Chris@0: len -= count; Chris@0: ptr += count; Chris@0: } Chris@0: Chris@0: return MAD_FLOW_CONTINUE; Chris@0: } Chris@0: Chris@0: static Chris@0: enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len) Chris@0: { Chris@0: int flags, blocking; Chris@0: enum mad_flow result; Chris@0: Chris@0: flags = fcntl(fd, F_GETFL); Chris@0: if (flags == -1) Chris@0: return MAD_FLOW_BREAK; Chris@0: Chris@0: blocking = flags & ~O_NONBLOCK; Chris@0: Chris@0: if (blocking != flags && Chris@0: fcntl(fd, F_SETFL, blocking) == -1) Chris@0: return MAD_FLOW_BREAK; Chris@0: Chris@0: result = receive_io(fd, buffer, len); Chris@0: Chris@0: if (flags != blocking && Chris@0: fcntl(fd, F_SETFL, flags) == -1) Chris@0: return MAD_FLOW_BREAK; Chris@0: Chris@0: return result; Chris@0: } Chris@0: Chris@0: static Chris@0: enum mad_flow send(int fd, void const *message, unsigned int size) Chris@0: { Chris@0: enum mad_flow result; Chris@0: Chris@0: /* send size */ Chris@0: Chris@0: result = send_io(fd, &size, sizeof(size)); Chris@0: Chris@0: /* send message */ Chris@0: Chris@0: if (result == MAD_FLOW_CONTINUE) Chris@0: result = send_io(fd, message, size); Chris@0: Chris@0: return result; Chris@0: } Chris@0: Chris@0: static Chris@0: enum mad_flow receive(int fd, void **message, unsigned int *size) Chris@0: { Chris@0: enum mad_flow result; Chris@0: unsigned int actual; Chris@0: Chris@0: if (*message == 0) Chris@0: *size = 0; Chris@0: Chris@0: /* receive size */ Chris@0: Chris@0: result = receive_io(fd, &actual, sizeof(actual)); Chris@0: Chris@0: /* receive message */ Chris@0: Chris@0: if (result == MAD_FLOW_CONTINUE) { Chris@0: if (actual > *size) Chris@0: actual -= *size; Chris@0: else { Chris@0: *size = actual; Chris@0: actual = 0; Chris@0: } Chris@0: Chris@0: if (*size > 0) { Chris@0: if (*message == 0) { Chris@0: *message = malloc(*size); Chris@0: if (*message == 0) Chris@0: return MAD_FLOW_BREAK; Chris@0: } Chris@0: Chris@0: result = receive_io_blocking(fd, *message, *size); Chris@0: } Chris@0: Chris@0: /* throw away remainder of message */ Chris@0: Chris@0: while (actual && result == MAD_FLOW_CONTINUE) { Chris@0: char sink[256]; Chris@0: unsigned int len; Chris@0: Chris@0: len = actual > sizeof(sink) ? sizeof(sink) : actual; Chris@0: Chris@0: result = receive_io_blocking(fd, sink, len); Chris@0: Chris@0: actual -= len; Chris@0: } Chris@0: } Chris@0: Chris@0: return result; Chris@0: } Chris@0: Chris@0: static Chris@0: enum mad_flow check_message(struct mad_decoder *decoder) Chris@0: { Chris@0: enum mad_flow result; Chris@0: void *message = 0; Chris@0: unsigned int size; Chris@0: Chris@0: result = receive(decoder->async.in, &message, &size); Chris@0: Chris@0: if (result == MAD_FLOW_CONTINUE) { Chris@0: if (decoder->message_func == 0) Chris@0: size = 0; Chris@0: else { Chris@0: result = decoder->message_func(decoder->cb_data, message, &size); Chris@0: Chris@0: if (result == MAD_FLOW_IGNORE || Chris@0: result == MAD_FLOW_BREAK) Chris@0: size = 0; Chris@0: } Chris@0: Chris@0: if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE) Chris@0: result = MAD_FLOW_BREAK; Chris@0: } Chris@0: Chris@0: if (message) Chris@0: free(message); Chris@0: Chris@0: return result; Chris@0: } Chris@0: # endif Chris@0: Chris@0: static Chris@0: enum mad_flow error_default(void *data, struct mad_stream *stream, Chris@0: struct mad_frame *frame) Chris@0: { Chris@0: int *bad_last_frame = data; Chris@0: Chris@0: switch (stream->error) { Chris@0: case MAD_ERROR_BADCRC: Chris@0: if (*bad_last_frame) Chris@0: mad_frame_mute(frame); Chris@0: else Chris@0: *bad_last_frame = 1; Chris@0: Chris@0: return MAD_FLOW_IGNORE; Chris@0: Chris@0: default: Chris@0: return MAD_FLOW_CONTINUE; Chris@0: } Chris@0: } Chris@0: Chris@0: static Chris@0: int run_sync(struct mad_decoder *decoder) Chris@0: { Chris@0: enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); Chris@0: void *error_data; Chris@0: int bad_last_frame = 0; Chris@0: struct mad_stream *stream; Chris@0: struct mad_frame *frame; Chris@0: struct mad_synth *synth; Chris@0: int result = 0; Chris@0: Chris@0: if (decoder->input_func == 0) Chris@0: return 0; Chris@0: Chris@0: if (decoder->error_func) { Chris@0: error_func = decoder->error_func; Chris@0: error_data = decoder->cb_data; Chris@0: } Chris@0: else { Chris@0: error_func = error_default; Chris@0: error_data = &bad_last_frame; Chris@0: } Chris@0: Chris@0: stream = &decoder->sync->stream; Chris@0: frame = &decoder->sync->frame; Chris@0: synth = &decoder->sync->synth; Chris@0: Chris@0: mad_stream_init(stream); Chris@0: mad_frame_init(frame); Chris@0: mad_synth_init(synth); Chris@0: Chris@0: mad_stream_options(stream, decoder->options); Chris@0: Chris@0: do { Chris@0: switch (decoder->input_func(decoder->cb_data, stream)) { Chris@0: case MAD_FLOW_STOP: Chris@0: goto done; Chris@0: case MAD_FLOW_BREAK: Chris@0: goto fail; Chris@0: case MAD_FLOW_IGNORE: Chris@0: continue; Chris@0: case MAD_FLOW_CONTINUE: Chris@0: break; Chris@0: } Chris@0: Chris@0: while (1) { Chris@0: # if defined(USE_ASYNC) Chris@0: if (decoder->mode == MAD_DECODER_MODE_ASYNC) { Chris@0: switch (check_message(decoder)) { Chris@0: case MAD_FLOW_IGNORE: Chris@0: case MAD_FLOW_CONTINUE: Chris@0: break; Chris@0: case MAD_FLOW_BREAK: Chris@0: goto fail; Chris@0: case MAD_FLOW_STOP: Chris@0: goto done; Chris@0: } Chris@0: } Chris@0: # endif Chris@0: Chris@0: if (decoder->header_func) { Chris@0: if (mad_header_decode(&frame->header, stream) == -1) { Chris@0: if (!MAD_RECOVERABLE(stream->error)) Chris@0: break; Chris@0: Chris@0: switch (error_func(error_data, stream, frame)) { Chris@0: case MAD_FLOW_STOP: Chris@0: goto done; Chris@0: case MAD_FLOW_BREAK: Chris@0: goto fail; Chris@0: case MAD_FLOW_IGNORE: Chris@0: case MAD_FLOW_CONTINUE: Chris@0: default: Chris@0: continue; Chris@0: } Chris@0: } Chris@0: Chris@0: switch (decoder->header_func(decoder->cb_data, &frame->header)) { Chris@0: case MAD_FLOW_STOP: Chris@0: goto done; Chris@0: case MAD_FLOW_BREAK: Chris@0: goto fail; Chris@0: case MAD_FLOW_IGNORE: Chris@0: continue; Chris@0: case MAD_FLOW_CONTINUE: Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: if (mad_frame_decode(frame, stream) == -1) { Chris@0: if (!MAD_RECOVERABLE(stream->error)) Chris@0: break; Chris@0: Chris@0: switch (error_func(error_data, stream, frame)) { Chris@0: case MAD_FLOW_STOP: Chris@0: goto done; Chris@0: case MAD_FLOW_BREAK: Chris@0: goto fail; Chris@0: case MAD_FLOW_IGNORE: Chris@0: break; Chris@0: case MAD_FLOW_CONTINUE: Chris@0: default: Chris@0: continue; Chris@0: } Chris@0: } Chris@0: else Chris@0: bad_last_frame = 0; Chris@0: Chris@0: if (decoder->filter_func) { Chris@0: switch (decoder->filter_func(decoder->cb_data, stream, frame)) { Chris@0: case MAD_FLOW_STOP: Chris@0: goto done; Chris@0: case MAD_FLOW_BREAK: Chris@0: goto fail; Chris@0: case MAD_FLOW_IGNORE: Chris@0: continue; Chris@0: case MAD_FLOW_CONTINUE: Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: mad_synth_frame(synth, frame); Chris@0: Chris@0: if (decoder->output_func) { Chris@0: switch (decoder->output_func(decoder->cb_data, Chris@0: &frame->header, &synth->pcm)) { Chris@0: case MAD_FLOW_STOP: Chris@0: goto done; Chris@0: case MAD_FLOW_BREAK: Chris@0: goto fail; Chris@0: case MAD_FLOW_IGNORE: Chris@0: case MAD_FLOW_CONTINUE: Chris@0: break; Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: while (stream->error == MAD_ERROR_BUFLEN); Chris@0: Chris@0: fail: Chris@0: result = -1; Chris@0: Chris@0: done: Chris@0: mad_synth_finish(synth); Chris@0: mad_frame_finish(frame); Chris@0: mad_stream_finish(stream); Chris@0: Chris@0: return result; Chris@0: } Chris@0: Chris@0: # if defined(USE_ASYNC) Chris@0: static Chris@0: int run_async(struct mad_decoder *decoder) Chris@0: { Chris@0: pid_t pid; Chris@0: int ptoc[2], ctop[2], flags; Chris@0: Chris@0: if (pipe(ptoc) == -1) Chris@0: return -1; Chris@0: Chris@0: if (pipe(ctop) == -1) { Chris@0: close(ptoc[0]); Chris@0: close(ptoc[1]); Chris@0: return -1; Chris@0: } Chris@0: Chris@0: flags = fcntl(ptoc[0], F_GETFL); Chris@0: if (flags == -1 || Chris@0: fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) { Chris@0: close(ctop[0]); Chris@0: close(ctop[1]); Chris@0: close(ptoc[0]); Chris@0: close(ptoc[1]); Chris@0: return -1; Chris@0: } Chris@0: Chris@0: pid = fork(); Chris@0: if (pid == -1) { Chris@0: close(ctop[0]); Chris@0: close(ctop[1]); Chris@0: close(ptoc[0]); Chris@0: close(ptoc[1]); Chris@0: return -1; Chris@0: } Chris@0: Chris@0: decoder->async.pid = pid; Chris@0: Chris@0: if (pid) { Chris@0: /* parent */ Chris@0: Chris@0: close(ptoc[0]); Chris@0: close(ctop[1]); Chris@0: Chris@0: decoder->async.in = ctop[0]; Chris@0: decoder->async.out = ptoc[1]; Chris@0: Chris@0: return 0; Chris@0: } Chris@0: Chris@0: /* child */ Chris@0: Chris@0: close(ptoc[1]); Chris@0: close(ctop[0]); Chris@0: Chris@0: decoder->async.in = ptoc[0]; Chris@0: decoder->async.out = ctop[1]; Chris@0: Chris@0: _exit(run_sync(decoder)); Chris@0: Chris@0: /* not reached */ Chris@0: return -1; Chris@0: } Chris@0: # endif Chris@0: Chris@0: /* Chris@0: * NAME: decoder->run() Chris@0: * DESCRIPTION: run the decoder thread either synchronously or asynchronously Chris@0: */ Chris@0: int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode) Chris@0: { Chris@0: int result; Chris@0: int (*run)(struct mad_decoder *) = 0; Chris@0: Chris@0: switch (decoder->mode = mode) { Chris@0: case MAD_DECODER_MODE_SYNC: Chris@0: run = run_sync; Chris@0: break; Chris@0: Chris@0: case MAD_DECODER_MODE_ASYNC: Chris@0: # if defined(USE_ASYNC) Chris@0: run = run_async; Chris@0: # endif Chris@0: break; Chris@0: } Chris@0: Chris@0: if (run == 0) Chris@0: return -1; Chris@0: Chris@0: decoder->sync = malloc(sizeof(*decoder->sync)); Chris@0: if (decoder->sync == 0) Chris@0: return -1; Chris@0: Chris@0: result = run(decoder); Chris@0: Chris@0: free(decoder->sync); Chris@0: decoder->sync = 0; Chris@0: Chris@0: return result; Chris@0: } Chris@0: Chris@0: /* Chris@0: * NAME: decoder->message() Chris@0: * DESCRIPTION: send a message to and receive a reply from the decoder process Chris@0: */ Chris@0: int mad_decoder_message(struct mad_decoder *decoder, Chris@0: void *message, unsigned int *len) Chris@0: { Chris@0: # if defined(USE_ASYNC) Chris@0: if (decoder->mode != MAD_DECODER_MODE_ASYNC || Chris@0: send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE || Chris@0: receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE) Chris@0: return -1; Chris@0: Chris@0: return 0; Chris@0: # else Chris@0: return -1; Chris@0: # endif Chris@0: }