mirror of
				https://github.com/alsa-project/alsa-tools.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			239 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			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();
 | 
						|
			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;
 | 
						|
}
 |