annotate src/libmad-0.15.1b/decoder.c @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 545efbb81310
children
rev   line source
cannam@85 1 /*
cannam@85 2 * libmad - MPEG audio decoder library
cannam@85 3 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
cannam@85 4 *
cannam@85 5 * This program is free software; you can redistribute it and/or modify
cannam@85 6 * it under the terms of the GNU General Public License as published by
cannam@85 7 * the Free Software Foundation; either version 2 of the License, or
cannam@85 8 * (at your option) any later version.
cannam@85 9 *
cannam@85 10 * This program is distributed in the hope that it will be useful,
cannam@85 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cannam@85 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cannam@85 13 * GNU General Public License for more details.
cannam@85 14 *
cannam@85 15 * You should have received a copy of the GNU General Public License
cannam@85 16 * along with this program; if not, write to the Free Software
cannam@85 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
cannam@85 18 *
cannam@85 19 * $Id: decoder.c,v 1.22 2004/01/23 09:41:32 rob Exp $
cannam@85 20 */
cannam@85 21
cannam@85 22 # ifdef HAVE_CONFIG_H
cannam@85 23 # include "config.h"
cannam@85 24 # endif
cannam@85 25
cannam@85 26 # include "global.h"
cannam@85 27
cannam@85 28 # ifdef HAVE_SYS_TYPES_H
cannam@85 29 # include <sys/types.h>
cannam@85 30 # endif
cannam@85 31
cannam@85 32 # ifdef HAVE_SYS_WAIT_H
cannam@85 33 # include <sys/wait.h>
cannam@85 34 # endif
cannam@85 35
cannam@85 36 # ifdef HAVE_UNISTD_H
cannam@85 37 # include <unistd.h>
cannam@85 38 # endif
cannam@85 39
cannam@85 40 # ifdef HAVE_FCNTL_H
cannam@85 41 # include <fcntl.h>
cannam@85 42 # endif
cannam@85 43
cannam@85 44 # include <stdlib.h>
cannam@85 45
cannam@85 46 # ifdef HAVE_ERRNO_H
cannam@85 47 # include <errno.h>
cannam@85 48 # endif
cannam@85 49
cannam@85 50 # include "stream.h"
cannam@85 51 # include "frame.h"
cannam@85 52 # include "synth.h"
cannam@85 53 # include "decoder.h"
cannam@85 54
cannam@85 55 /*
cannam@85 56 * NAME: decoder->init()
cannam@85 57 * DESCRIPTION: initialize a decoder object with callback routines
cannam@85 58 */
cannam@85 59 void mad_decoder_init(struct mad_decoder *decoder, void *data,
cannam@85 60 enum mad_flow (*input_func)(void *,
cannam@85 61 struct mad_stream *),
cannam@85 62 enum mad_flow (*header_func)(void *,
cannam@85 63 struct mad_header const *),
cannam@85 64 enum mad_flow (*filter_func)(void *,
cannam@85 65 struct mad_stream const *,
cannam@85 66 struct mad_frame *),
cannam@85 67 enum mad_flow (*output_func)(void *,
cannam@85 68 struct mad_header const *,
cannam@85 69 struct mad_pcm *),
cannam@85 70 enum mad_flow (*error_func)(void *,
cannam@85 71 struct mad_stream *,
cannam@85 72 struct mad_frame *),
cannam@85 73 enum mad_flow (*message_func)(void *,
cannam@85 74 void *, unsigned int *))
cannam@85 75 {
cannam@85 76 decoder->mode = -1;
cannam@85 77
cannam@85 78 decoder->options = 0;
cannam@85 79
cannam@85 80 decoder->async.pid = 0;
cannam@85 81 decoder->async.in = -1;
cannam@85 82 decoder->async.out = -1;
cannam@85 83
cannam@85 84 decoder->sync = 0;
cannam@85 85
cannam@85 86 decoder->cb_data = data;
cannam@85 87
cannam@85 88 decoder->input_func = input_func;
cannam@85 89 decoder->header_func = header_func;
cannam@85 90 decoder->filter_func = filter_func;
cannam@85 91 decoder->output_func = output_func;
cannam@85 92 decoder->error_func = error_func;
cannam@85 93 decoder->message_func = message_func;
cannam@85 94 }
cannam@85 95
cannam@85 96 int mad_decoder_finish(struct mad_decoder *decoder)
cannam@85 97 {
cannam@85 98 # if defined(USE_ASYNC)
cannam@85 99 if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) {
cannam@85 100 pid_t pid;
cannam@85 101 int status;
cannam@85 102
cannam@85 103 close(decoder->async.in);
cannam@85 104
cannam@85 105 do
cannam@85 106 pid = waitpid(decoder->async.pid, &status, 0);
cannam@85 107 while (pid == -1 && errno == EINTR);
cannam@85 108
cannam@85 109 decoder->mode = -1;
cannam@85 110
cannam@85 111 close(decoder->async.out);
cannam@85 112
cannam@85 113 decoder->async.pid = 0;
cannam@85 114 decoder->async.in = -1;
cannam@85 115 decoder->async.out = -1;
cannam@85 116
cannam@85 117 if (pid == -1)
cannam@85 118 return -1;
cannam@85 119
cannam@85 120 return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0;
cannam@85 121 }
cannam@85 122 # endif
cannam@85 123
cannam@85 124 return 0;
cannam@85 125 }
cannam@85 126
cannam@85 127 # if defined(USE_ASYNC)
cannam@85 128 static
cannam@85 129 enum mad_flow send_io(int fd, void const *data, size_t len)
cannam@85 130 {
cannam@85 131 char const *ptr = data;
cannam@85 132 ssize_t count;
cannam@85 133
cannam@85 134 while (len) {
cannam@85 135 do
cannam@85 136 count = write(fd, ptr, len);
cannam@85 137 while (count == -1 && errno == EINTR);
cannam@85 138
cannam@85 139 if (count == -1)
cannam@85 140 return MAD_FLOW_BREAK;
cannam@85 141
cannam@85 142 len -= count;
cannam@85 143 ptr += count;
cannam@85 144 }
cannam@85 145
cannam@85 146 return MAD_FLOW_CONTINUE;
cannam@85 147 }
cannam@85 148
cannam@85 149 static
cannam@85 150 enum mad_flow receive_io(int fd, void *buffer, size_t len)
cannam@85 151 {
cannam@85 152 char *ptr = buffer;
cannam@85 153 ssize_t count;
cannam@85 154
cannam@85 155 while (len) {
cannam@85 156 do
cannam@85 157 count = read(fd, ptr, len);
cannam@85 158 while (count == -1 && errno == EINTR);
cannam@85 159
cannam@85 160 if (count == -1)
cannam@85 161 return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK;
cannam@85 162 else if (count == 0)
cannam@85 163 return MAD_FLOW_STOP;
cannam@85 164
cannam@85 165 len -= count;
cannam@85 166 ptr += count;
cannam@85 167 }
cannam@85 168
cannam@85 169 return MAD_FLOW_CONTINUE;
cannam@85 170 }
cannam@85 171
cannam@85 172 static
cannam@85 173 enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len)
cannam@85 174 {
cannam@85 175 int flags, blocking;
cannam@85 176 enum mad_flow result;
cannam@85 177
cannam@85 178 flags = fcntl(fd, F_GETFL);
cannam@85 179 if (flags == -1)
cannam@85 180 return MAD_FLOW_BREAK;
cannam@85 181
cannam@85 182 blocking = flags & ~O_NONBLOCK;
cannam@85 183
cannam@85 184 if (blocking != flags &&
cannam@85 185 fcntl(fd, F_SETFL, blocking) == -1)
cannam@85 186 return MAD_FLOW_BREAK;
cannam@85 187
cannam@85 188 result = receive_io(fd, buffer, len);
cannam@85 189
cannam@85 190 if (flags != blocking &&
cannam@85 191 fcntl(fd, F_SETFL, flags) == -1)
cannam@85 192 return MAD_FLOW_BREAK;
cannam@85 193
cannam@85 194 return result;
cannam@85 195 }
cannam@85 196
cannam@85 197 static
cannam@85 198 enum mad_flow send(int fd, void const *message, unsigned int size)
cannam@85 199 {
cannam@85 200 enum mad_flow result;
cannam@85 201
cannam@85 202 /* send size */
cannam@85 203
cannam@85 204 result = send_io(fd, &size, sizeof(size));
cannam@85 205
cannam@85 206 /* send message */
cannam@85 207
cannam@85 208 if (result == MAD_FLOW_CONTINUE)
cannam@85 209 result = send_io(fd, message, size);
cannam@85 210
cannam@85 211 return result;
cannam@85 212 }
cannam@85 213
cannam@85 214 static
cannam@85 215 enum mad_flow receive(int fd, void **message, unsigned int *size)
cannam@85 216 {
cannam@85 217 enum mad_flow result;
cannam@85 218 unsigned int actual;
cannam@85 219
cannam@85 220 if (*message == 0)
cannam@85 221 *size = 0;
cannam@85 222
cannam@85 223 /* receive size */
cannam@85 224
cannam@85 225 result = receive_io(fd, &actual, sizeof(actual));
cannam@85 226
cannam@85 227 /* receive message */
cannam@85 228
cannam@85 229 if (result == MAD_FLOW_CONTINUE) {
cannam@85 230 if (actual > *size)
cannam@85 231 actual -= *size;
cannam@85 232 else {
cannam@85 233 *size = actual;
cannam@85 234 actual = 0;
cannam@85 235 }
cannam@85 236
cannam@85 237 if (*size > 0) {
cannam@85 238 if (*message == 0) {
cannam@85 239 *message = malloc(*size);
cannam@85 240 if (*message == 0)
cannam@85 241 return MAD_FLOW_BREAK;
cannam@85 242 }
cannam@85 243
cannam@85 244 result = receive_io_blocking(fd, *message, *size);
cannam@85 245 }
cannam@85 246
cannam@85 247 /* throw away remainder of message */
cannam@85 248
cannam@85 249 while (actual && result == MAD_FLOW_CONTINUE) {
cannam@85 250 char sink[256];
cannam@85 251 unsigned int len;
cannam@85 252
cannam@85 253 len = actual > sizeof(sink) ? sizeof(sink) : actual;
cannam@85 254
cannam@85 255 result = receive_io_blocking(fd, sink, len);
cannam@85 256
cannam@85 257 actual -= len;
cannam@85 258 }
cannam@85 259 }
cannam@85 260
cannam@85 261 return result;
cannam@85 262 }
cannam@85 263
cannam@85 264 static
cannam@85 265 enum mad_flow check_message(struct mad_decoder *decoder)
cannam@85 266 {
cannam@85 267 enum mad_flow result;
cannam@85 268 void *message = 0;
cannam@85 269 unsigned int size;
cannam@85 270
cannam@85 271 result = receive(decoder->async.in, &message, &size);
cannam@85 272
cannam@85 273 if (result == MAD_FLOW_CONTINUE) {
cannam@85 274 if (decoder->message_func == 0)
cannam@85 275 size = 0;
cannam@85 276 else {
cannam@85 277 result = decoder->message_func(decoder->cb_data, message, &size);
cannam@85 278
cannam@85 279 if (result == MAD_FLOW_IGNORE ||
cannam@85 280 result == MAD_FLOW_BREAK)
cannam@85 281 size = 0;
cannam@85 282 }
cannam@85 283
cannam@85 284 if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE)
cannam@85 285 result = MAD_FLOW_BREAK;
cannam@85 286 }
cannam@85 287
cannam@85 288 if (message)
cannam@85 289 free(message);
cannam@85 290
cannam@85 291 return result;
cannam@85 292 }
cannam@85 293 # endif
cannam@85 294
cannam@85 295 static
cannam@85 296 enum mad_flow error_default(void *data, struct mad_stream *stream,
cannam@85 297 struct mad_frame *frame)
cannam@85 298 {
cannam@85 299 int *bad_last_frame = data;
cannam@85 300
cannam@85 301 switch (stream->error) {
cannam@85 302 case MAD_ERROR_BADCRC:
cannam@85 303 if (*bad_last_frame)
cannam@85 304 mad_frame_mute(frame);
cannam@85 305 else
cannam@85 306 *bad_last_frame = 1;
cannam@85 307
cannam@85 308 return MAD_FLOW_IGNORE;
cannam@85 309
cannam@85 310 default:
cannam@85 311 return MAD_FLOW_CONTINUE;
cannam@85 312 }
cannam@85 313 }
cannam@85 314
cannam@85 315 static
cannam@85 316 int run_sync(struct mad_decoder *decoder)
cannam@85 317 {
cannam@85 318 enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
cannam@85 319 void *error_data;
cannam@85 320 int bad_last_frame = 0;
cannam@85 321 struct mad_stream *stream;
cannam@85 322 struct mad_frame *frame;
cannam@85 323 struct mad_synth *synth;
cannam@85 324 int result = 0;
cannam@85 325
cannam@85 326 if (decoder->input_func == 0)
cannam@85 327 return 0;
cannam@85 328
cannam@85 329 if (decoder->error_func) {
cannam@85 330 error_func = decoder->error_func;
cannam@85 331 error_data = decoder->cb_data;
cannam@85 332 }
cannam@85 333 else {
cannam@85 334 error_func = error_default;
cannam@85 335 error_data = &bad_last_frame;
cannam@85 336 }
cannam@85 337
cannam@85 338 stream = &decoder->sync->stream;
cannam@85 339 frame = &decoder->sync->frame;
cannam@85 340 synth = &decoder->sync->synth;
cannam@85 341
cannam@85 342 mad_stream_init(stream);
cannam@85 343 mad_frame_init(frame);
cannam@85 344 mad_synth_init(synth);
cannam@85 345
cannam@85 346 mad_stream_options(stream, decoder->options);
cannam@85 347
cannam@85 348 do {
cannam@85 349 switch (decoder->input_func(decoder->cb_data, stream)) {
cannam@85 350 case MAD_FLOW_STOP:
cannam@85 351 goto done;
cannam@85 352 case MAD_FLOW_BREAK:
cannam@85 353 goto fail;
cannam@85 354 case MAD_FLOW_IGNORE:
cannam@85 355 continue;
cannam@85 356 case MAD_FLOW_CONTINUE:
cannam@85 357 break;
cannam@85 358 }
cannam@85 359
cannam@85 360 while (1) {
cannam@85 361 # if defined(USE_ASYNC)
cannam@85 362 if (decoder->mode == MAD_DECODER_MODE_ASYNC) {
cannam@85 363 switch (check_message(decoder)) {
cannam@85 364 case MAD_FLOW_IGNORE:
cannam@85 365 case MAD_FLOW_CONTINUE:
cannam@85 366 break;
cannam@85 367 case MAD_FLOW_BREAK:
cannam@85 368 goto fail;
cannam@85 369 case MAD_FLOW_STOP:
cannam@85 370 goto done;
cannam@85 371 }
cannam@85 372 }
cannam@85 373 # endif
cannam@85 374
cannam@85 375 if (decoder->header_func) {
cannam@85 376 if (mad_header_decode(&frame->header, stream) == -1) {
cannam@85 377 if (!MAD_RECOVERABLE(stream->error))
cannam@85 378 break;
cannam@85 379
cannam@85 380 switch (error_func(error_data, stream, frame)) {
cannam@85 381 case MAD_FLOW_STOP:
cannam@85 382 goto done;
cannam@85 383 case MAD_FLOW_BREAK:
cannam@85 384 goto fail;
cannam@85 385 case MAD_FLOW_IGNORE:
cannam@85 386 case MAD_FLOW_CONTINUE:
cannam@85 387 default:
cannam@85 388 continue;
cannam@85 389 }
cannam@85 390 }
cannam@85 391
cannam@85 392 switch (decoder->header_func(decoder->cb_data, &frame->header)) {
cannam@85 393 case MAD_FLOW_STOP:
cannam@85 394 goto done;
cannam@85 395 case MAD_FLOW_BREAK:
cannam@85 396 goto fail;
cannam@85 397 case MAD_FLOW_IGNORE:
cannam@85 398 continue;
cannam@85 399 case MAD_FLOW_CONTINUE:
cannam@85 400 break;
cannam@85 401 }
cannam@85 402 }
cannam@85 403
cannam@85 404 if (mad_frame_decode(frame, stream) == -1) {
cannam@85 405 if (!MAD_RECOVERABLE(stream->error))
cannam@85 406 break;
cannam@85 407
cannam@85 408 switch (error_func(error_data, stream, frame)) {
cannam@85 409 case MAD_FLOW_STOP:
cannam@85 410 goto done;
cannam@85 411 case MAD_FLOW_BREAK:
cannam@85 412 goto fail;
cannam@85 413 case MAD_FLOW_IGNORE:
cannam@85 414 break;
cannam@85 415 case MAD_FLOW_CONTINUE:
cannam@85 416 default:
cannam@85 417 continue;
cannam@85 418 }
cannam@85 419 }
cannam@85 420 else
cannam@85 421 bad_last_frame = 0;
cannam@85 422
cannam@85 423 if (decoder->filter_func) {
cannam@85 424 switch (decoder->filter_func(decoder->cb_data, stream, frame)) {
cannam@85 425 case MAD_FLOW_STOP:
cannam@85 426 goto done;
cannam@85 427 case MAD_FLOW_BREAK:
cannam@85 428 goto fail;
cannam@85 429 case MAD_FLOW_IGNORE:
cannam@85 430 continue;
cannam@85 431 case MAD_FLOW_CONTINUE:
cannam@85 432 break;
cannam@85 433 }
cannam@85 434 }
cannam@85 435
cannam@85 436 mad_synth_frame(synth, frame);
cannam@85 437
cannam@85 438 if (decoder->output_func) {
cannam@85 439 switch (decoder->output_func(decoder->cb_data,
cannam@85 440 &frame->header, &synth->pcm)) {
cannam@85 441 case MAD_FLOW_STOP:
cannam@85 442 goto done;
cannam@85 443 case MAD_FLOW_BREAK:
cannam@85 444 goto fail;
cannam@85 445 case MAD_FLOW_IGNORE:
cannam@85 446 case MAD_FLOW_CONTINUE:
cannam@85 447 break;
cannam@85 448 }
cannam@85 449 }
cannam@85 450 }
cannam@85 451 }
cannam@85 452 while (stream->error == MAD_ERROR_BUFLEN);
cannam@85 453
cannam@85 454 fail:
cannam@85 455 result = -1;
cannam@85 456
cannam@85 457 done:
cannam@85 458 mad_synth_finish(synth);
cannam@85 459 mad_frame_finish(frame);
cannam@85 460 mad_stream_finish(stream);
cannam@85 461
cannam@85 462 return result;
cannam@85 463 }
cannam@85 464
cannam@85 465 # if defined(USE_ASYNC)
cannam@85 466 static
cannam@85 467 int run_async(struct mad_decoder *decoder)
cannam@85 468 {
cannam@85 469 pid_t pid;
cannam@85 470 int ptoc[2], ctop[2], flags;
cannam@85 471
cannam@85 472 if (pipe(ptoc) == -1)
cannam@85 473 return -1;
cannam@85 474
cannam@85 475 if (pipe(ctop) == -1) {
cannam@85 476 close(ptoc[0]);
cannam@85 477 close(ptoc[1]);
cannam@85 478 return -1;
cannam@85 479 }
cannam@85 480
cannam@85 481 flags = fcntl(ptoc[0], F_GETFL);
cannam@85 482 if (flags == -1 ||
cannam@85 483 fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) {
cannam@85 484 close(ctop[0]);
cannam@85 485 close(ctop[1]);
cannam@85 486 close(ptoc[0]);
cannam@85 487 close(ptoc[1]);
cannam@85 488 return -1;
cannam@85 489 }
cannam@85 490
cannam@85 491 pid = fork();
cannam@85 492 if (pid == -1) {
cannam@85 493 close(ctop[0]);
cannam@85 494 close(ctop[1]);
cannam@85 495 close(ptoc[0]);
cannam@85 496 close(ptoc[1]);
cannam@85 497 return -1;
cannam@85 498 }
cannam@85 499
cannam@85 500 decoder->async.pid = pid;
cannam@85 501
cannam@85 502 if (pid) {
cannam@85 503 /* parent */
cannam@85 504
cannam@85 505 close(ptoc[0]);
cannam@85 506 close(ctop[1]);
cannam@85 507
cannam@85 508 decoder->async.in = ctop[0];
cannam@85 509 decoder->async.out = ptoc[1];
cannam@85 510
cannam@85 511 return 0;
cannam@85 512 }
cannam@85 513
cannam@85 514 /* child */
cannam@85 515
cannam@85 516 close(ptoc[1]);
cannam@85 517 close(ctop[0]);
cannam@85 518
cannam@85 519 decoder->async.in = ptoc[0];
cannam@85 520 decoder->async.out = ctop[1];
cannam@85 521
cannam@85 522 _exit(run_sync(decoder));
cannam@85 523
cannam@85 524 /* not reached */
cannam@85 525 return -1;
cannam@85 526 }
cannam@85 527 # endif
cannam@85 528
cannam@85 529 /*
cannam@85 530 * NAME: decoder->run()
cannam@85 531 * DESCRIPTION: run the decoder thread either synchronously or asynchronously
cannam@85 532 */
cannam@85 533 int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode)
cannam@85 534 {
cannam@85 535 int result;
cannam@85 536 int (*run)(struct mad_decoder *) = 0;
cannam@85 537
cannam@85 538 switch (decoder->mode = mode) {
cannam@85 539 case MAD_DECODER_MODE_SYNC:
cannam@85 540 run = run_sync;
cannam@85 541 break;
cannam@85 542
cannam@85 543 case MAD_DECODER_MODE_ASYNC:
cannam@85 544 # if defined(USE_ASYNC)
cannam@85 545 run = run_async;
cannam@85 546 # endif
cannam@85 547 break;
cannam@85 548 }
cannam@85 549
cannam@85 550 if (run == 0)
cannam@85 551 return -1;
cannam@85 552
cannam@85 553 decoder->sync = malloc(sizeof(*decoder->sync));
cannam@85 554 if (decoder->sync == 0)
cannam@85 555 return -1;
cannam@85 556
cannam@85 557 result = run(decoder);
cannam@85 558
cannam@85 559 free(decoder->sync);
cannam@85 560 decoder->sync = 0;
cannam@85 561
cannam@85 562 return result;
cannam@85 563 }
cannam@85 564
cannam@85 565 /*
cannam@85 566 * NAME: decoder->message()
cannam@85 567 * DESCRIPTION: send a message to and receive a reply from the decoder process
cannam@85 568 */
cannam@85 569 int mad_decoder_message(struct mad_decoder *decoder,
cannam@85 570 void *message, unsigned int *len)
cannam@85 571 {
cannam@85 572 # if defined(USE_ASYNC)
cannam@85 573 if (decoder->mode != MAD_DECODER_MODE_ASYNC ||
cannam@85 574 send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE ||
cannam@85 575 receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE)
cannam@85 576 return -1;
cannam@85 577
cannam@85 578 return 0;
cannam@85 579 # else
cannam@85 580 return -1;
cannam@85 581 # endif
cannam@85 582 }