Logo Search packages:      
Sourcecode: alsa-tools version File versions  Download package

ac3dec.c

/* 
 *   ac3dec.c
 *
 *    Copyright (C) Aaron Holtzman - May 1999
 *
 *  This file is part of ac3dec, a free Dolby AC-3 stream decoder.
 *    
 *  ac3dec is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  ac3dec is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include <errno.h>
#include "config.h"

#include "libac3/ac3.h"
#include "output.h"

void init_spdif(void);
int output_spdif_zero(int frames);
int output_spdif_leadin(void);
int output_spdif(uint_8 *data_start, uint_8 *data_end, int quiet);

static int end_flag = 0;
static int quiet = 0;

static void help(void)
{
      printf("Usage: ac3dec <options> [file] [[file]] ...\n");
      printf("\nAvailable options:\n");
      printf("  -h,--help         this help\n");
      printf("  -v,--version      print version of this program\n");
      printf("  -D,--device=NAME  select PCM by NAME\n");
      printf("  -c,--card=ID      select card for bellow modes\n");
      printf("  -4,--4ch          four channels mode\n");
      printf("  -6,--6ch          six channels mode\n");
      printf("  -C,--iec958c      raw IEC958 (S/PDIF) consumer mode\n");
      printf("  -P,--iec958p      raw IEC958 (S/PDIF) professional mode\n");
      printf("  -R,--iec958r      raw IEC958 (S/PDIF) PCM\n");
      printf("  -Z,--zero=#       add # zero-AC3-frames before stream\n");
      printf("  -q,--quit         quit mode\n");
}

#define CHUNK_SIZE 2047
uint_8 buf[CHUNK_SIZE];
FILE *in_file;
 
ssize_t fill_buffer(uint_8 **start,uint_8 **end)
{
      uint_32 bytes_read;

      *start = buf;

      bytes_read = fread(*start,1,CHUNK_SIZE,in_file);

      if (feof(in_file) || ferror(in_file) || bytes_read < CHUNK_SIZE) {
            end_flag = 1;
            return EOF;
      }

      *end = *start + bytes_read;
      return bytes_read;
}

static void ac3dec_signal_handler(int signal)
{
      if (!quiet)
            fprintf(stderr, "Aborted...\n");
      // it's important to close the PCM handle(s), because
      // some driver settings have to be recovered
      output_close();
      fclose(in_file);
      exit(EXIT_FAILURE);
}

int main(int argc,char *argv[])
{
      struct option long_option[] =
      {
            {"help", 0, NULL, 'h'},
            {"version", 0, NULL, 'v'},
            {"device", 1, NULL, 'D'},
            {"4ch", 0, NULL, '4'},
            {"6ch", 0, NULL, '6'},
            {"card", 1, NULL, 'c'},
            {"iec958c", 0, NULL, 'C'},
            {"spdif", 0, NULL, 'C'},
            {"iec958p", 0, NULL, 'P'},
            {"iec958r", 0, NULL, 'R'},
            {"zero", 1, NULL, 'Z'},
            {"quit", 0, NULL, 'q'},
            {NULL, 0, NULL, 0},
      };
      ac3_config_t ac3_config;
      output_t out_config;
      int morehelp, loop = 0;
      int zero = 0;

      bzero(&ac3_config, sizeof(ac3_config));
      ac3_config.fill_buffer_callback = fill_buffer;
      ac3_config.num_output_ch = 2;
      ac3_config.flags = 0;
      bzero(&out_config, sizeof(out_config));
      out_config.pcm_name = NULL;
      out_config.card = NULL;
      out_config.bits = 16;
      out_config.rate = 48000;
      out_config.channels = 2;
      out_config.spdif = SPDIF_NONE;

      morehelp = 0;
      while (1) {
            int c;

            if ((c = getopt_long(argc, argv, "hvc:D:46CPRZ:q", long_option, NULL)) < 0)
                  break;
            switch (c) {
            case 'h':
                  morehelp++;
                  break;
            case 'v':
                  printf("ac3dec version " VERSION "\n");
                  return 1;
            case 'c':
                  out_config.card = strdup(optarg);
                  break;
            case 'D':
                  out_config.pcm_name = optarg;
                  break;
            case '4':
                  if (out_config.spdif == SPDIF_NONE)
                        ac3_config.num_output_ch = 4;
                  break;
            case '6':
                  if (out_config.spdif == SPDIF_NONE)
                        ac3_config.num_output_ch = 6;
                  break;
            case 'C':
                  ac3_config.num_output_ch = 2;
                  out_config.spdif = SPDIF_CON;
                  break;
            case 'P':
                  ac3_config.num_output_ch = 2;
                  out_config.spdif = SPDIF_PRO;
                  break;
            case 'R':
                  ac3_config.num_output_ch = 2;
                  out_config.spdif = SPDIF_PCM;
                  break;
            case 'Z':
                  zero = atoi(optarg);
                  break;
            case 'q':
                  ac3_config.flags |= AC3_QUIET;
                  out_config.quiet = 1;
                  quiet = 1;
                  break;
            default:
                  fprintf(stderr, "\07Invalid switch or option needs an argument.\n");
                  morehelp++;
            }
      }
      out_config.channels = ac3_config.num_output_ch;
      if (morehelp) {
            help();
            return 1;
      }

      while (1) {
            if (argc - optind <= 0) {
                  if (loop || end_flag)
                        break;
                  in_file = stdin;
            } else {
                  in_file = fopen(argv[optind],"r");  
                  if(!in_file) {
                        fprintf(stderr,"%s - Couldn't open file %s\n",strerror(errno),argv[optind]);
                        exit(EXIT_FAILURE);
                  }
                  optind++;
                  loop++;
            }
            if ((out_config.spdif == SPDIF_NONE) || (out_config.spdif == SPDIF_PCM)) {
                  ac3_frame_t *ac3_frame;
                  ac3_init(&ac3_config);
                  ac3_frame = ac3_decode_frame();
                  out_config.rate = ac3_frame->sampling_rate;
                  if (output_open(&out_config) < 0) {
                        fprintf(stderr, "Output open failed\n");
                        exit(EXIT_FAILURE);
                  }
                  signal(SIGINT, ac3dec_signal_handler);
                  signal(SIGTERM, ac3dec_signal_handler);
                  signal(SIGABRT, ac3dec_signal_handler);
                  do {
                        //Send the samples to the output device 
                        output_play(ac3_frame->audio_data, 256 * 6);
                  } while((ac3_frame = ac3_decode_frame()));
            } else {
                  uint_8 *start, *end;
                  init_spdif();
                  if (output_open(&out_config) < 0) {
                        fprintf(stderr, "Output open failed\n");
                        exit(EXIT_FAILURE);
                  }
                  signal(SIGINT, ac3dec_signal_handler);
                  signal(SIGTERM, ac3dec_signal_handler);
                  signal(SIGABRT, ac3dec_signal_handler);
                  if (zero > 0)
                        output_spdif_zero(zero);
                  else
                        output_spdif_leadin();
                  while (fill_buffer(&start, &end) > 0)
                        if (output_spdif(start, end, quiet) < 0)
                              break;
            }
            output_close();
            fclose(in_file);
      }
      return EXIT_SUCCESS;
}

Generated by  Doxygen 1.6.0   Back to index