| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | /* 
 | 
					
						
							|  |  |  |  *   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>
 | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | #include <getopt.h>
 | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | #include <sys/errno.h>
 | 
					
						
							| 
									
										
										
										
											2001-05-10 08:26:29 +00:00
										 |  |  | #include <sys/signal.h>
 | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | #include <errno.h>
 | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | #include "config.h"
 | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "libac3/ac3.h"
 | 
					
						
							|  |  |  | #include "output.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-05 11:50:02 +00:00
										 |  |  | 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); | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-06-26 15:23:21 +00:00
										 |  |  | static int end_flag = 0; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 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"); | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 	printf("  -c,--card=ID      select card for bellow modes\n"); | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	printf("  -4,--4ch	    four channels mode\n"); | 
					
						
							|  |  |  | 	printf("  -6,--6ch	    six channels mode\n"); | 
					
						
							| 
									
										
										
										
											2001-04-22 14:44:23 +00:00
										 |  |  | 	printf("  -C,--iec958c      raw IEC958 (S/PDIF) consumer mode\n"); | 
					
						
							|  |  |  | 	printf("  -P,--iec958p      raw IEC958 (S/PDIF) professional mode\n"); | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 	printf("  -R,--iec958r      raw IEC958 (S/PDIF) PCM\n"); | 
					
						
							| 
									
										
										
										
											2001-08-05 11:50:02 +00:00
										 |  |  | 	printf("  -Z,--zero=#       add # zero-AC3-frames before stream\n"); | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	printf("  -q,--quit         quit mode\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | #define CHUNK_SIZE 2047
 | 
					
						
							|  |  |  | uint_8 buf[CHUNK_SIZE]; | 
					
						
							|  |  |  | FILE *in_file; | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | ssize_t fill_buffer(uint_8 **start,uint_8 **end) | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	uint_32 bytes_read; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*start = buf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bytes_read = fread(*start,1,CHUNK_SIZE,in_file); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-06-26 15:23:21 +00:00
										 |  |  | 	if (feof(in_file) || ferror(in_file) || bytes_read < CHUNK_SIZE) { | 
					
						
							|  |  |  | 		end_flag = 1; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 		return EOF; | 
					
						
							| 
									
										
										
										
											2001-06-26 15:23:21 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	*end = *start + bytes_read; | 
					
						
							|  |  |  | 	return bytes_read; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-05-10 08:26:29 +00:00
										 |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | int main(int argc,char *argv[]) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	struct option long_option[] = | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		{"help", 0, NULL, 'h'}, | 
					
						
							|  |  |  | 		{"version", 0, NULL, 'v'}, | 
					
						
							|  |  |  | 		{"device", 1, NULL, 'D'}, | 
					
						
							|  |  |  | 		{"4ch", 0, NULL, '4'}, | 
					
						
							|  |  |  | 		{"6ch", 0, NULL, '6'}, | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 		{"card", 0, NULL, 'c'}, | 
					
						
							| 
									
										
										
										
											2001-04-22 14:44:23 +00:00
										 |  |  | 		{"iec958c", 0, NULL, 'C'}, | 
					
						
							|  |  |  | 		{"spdif", 0, NULL, 'C'}, | 
					
						
							|  |  |  | 		{"iec958p", 0, NULL, 'P'}, | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 		{"iec958r", 0, NULL, 'R'}, | 
					
						
							| 
									
										
										
										
											2001-08-05 11:50:02 +00:00
										 |  |  | 		{"zero", 1, NULL, 'Z'}, | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 		{"quit", 0, NULL, 'q'}, | 
					
						
							|  |  |  | 		{NULL, 0, NULL, 0}, | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 	ac3_config_t ac3_config; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	output_t out_config; | 
					
						
							|  |  |  | 	int morehelp, loop = 0; | 
					
						
							| 
									
										
										
										
											2001-08-05 11:50:02 +00:00
										 |  |  | 	int zero = 0; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	bzero(&ac3_config, sizeof(ac3_config)); | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 	ac3_config.fill_buffer_callback = fill_buffer; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	ac3_config.num_output_ch = 2; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 	ac3_config.flags = 0; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	bzero(&out_config, sizeof(out_config)); | 
					
						
							|  |  |  | 	out_config.pcm_name = NULL; | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 	out_config.card = NULL; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	out_config.bits = 16; | 
					
						
							|  |  |  | 	out_config.rate = 48000; | 
					
						
							|  |  |  | 	out_config.channels = 2; | 
					
						
							| 
									
										
										
										
											2001-04-22 14:44:23 +00:00
										 |  |  | 	out_config.spdif = SPDIF_NONE; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	morehelp = 0; | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							|  |  |  | 		int c; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-06 16:08:32 +00:00
										 |  |  | 		if ((c = getopt_long(argc, argv, "hvcD:46CPRZ:q", long_option, NULL)) < 0) | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		switch (c) { | 
					
						
							|  |  |  | 		case 'h': | 
					
						
							|  |  |  | 			morehelp++; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'v': | 
					
						
							|  |  |  | 			printf("ac3dec version " VERSION "\n"); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 		case 'c': | 
					
						
							|  |  |  | 			out_config.card = strdup(optarg); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 		case 'D': | 
					
						
							| 
									
										
										
										
											2001-04-22 14:44:23 +00:00
										 |  |  | 			out_config.pcm_name = optarg; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case '4': | 
					
						
							| 
									
										
										
										
											2001-04-23 17:46:19 +00:00
										 |  |  | 			if (out_config.spdif == SPDIF_NONE) | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 				ac3_config.num_output_ch = 4; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case '6': | 
					
						
							| 
									
										
										
										
											2001-04-23 17:46:19 +00:00
										 |  |  | 			if (out_config.spdif == SPDIF_NONE) | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 				ac3_config.num_output_ch = 6; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2001-04-22 14:44:23 +00:00
										 |  |  | 		case 'C': | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 			ac3_config.num_output_ch = 2; | 
					
						
							| 
									
										
										
										
											2001-04-22 14:44:23 +00:00
										 |  |  | 			out_config.spdif = SPDIF_CON; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'P': | 
					
						
							|  |  |  | 			ac3_config.num_output_ch = 2; | 
					
						
							|  |  |  | 			out_config.spdif = SPDIF_PRO; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 		case 'R': | 
					
						
							|  |  |  | 			ac3_config.num_output_ch = 2; | 
					
						
							|  |  |  | 			out_config.spdif = SPDIF_PCM; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2001-08-05 11:50:02 +00:00
										 |  |  | 		case 'Z': | 
					
						
							|  |  |  | 			zero = atoi(optarg); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 	while (1) { | 
					
						
							|  |  |  | 		if (argc - optind <= 0) { | 
					
						
							| 
									
										
										
										
											2001-06-26 15:23:21 +00:00
										 |  |  | 			if (loop || end_flag) | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 				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++; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2001-07-30 08:33:17 +00:00
										 |  |  | 		if ((out_config.spdif == SPDIF_NONE) || (out_config.spdif == SPDIF_PCM)) { | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 			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); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2001-05-10 08:26:29 +00:00
										 |  |  | 			signal(SIGINT, ac3dec_signal_handler); | 
					
						
							|  |  |  | 			signal(SIGTERM, ac3dec_signal_handler); | 
					
						
							|  |  |  | 			signal(SIGABRT, ac3dec_signal_handler); | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 			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(); | 
					
						
							| 
									
										
										
										
											2001-05-10 08:26:29 +00:00
										 |  |  | 			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); | 
					
						
							| 
									
										
										
										
											2001-08-05 11:50:02 +00:00
										 |  |  | 			if (zero > 0) | 
					
						
							|  |  |  | 				output_spdif_zero(zero); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				output_spdif_leadin(); | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 			while (fill_buffer(&start, &end) > 0) | 
					
						
							| 
									
										
										
										
											2001-06-15 09:12:37 +00:00
										 |  |  | 				if (output_spdif(start, end, quiet) < 0) | 
					
						
							| 
									
										
										
										
											2001-04-22 12:04:00 +00:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		output_close(); | 
					
						
							|  |  |  | 		fclose(in_file); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return EXIT_SUCCESS; | 
					
						
							| 
									
										
										
										
											2001-04-17 19:31:03 +00:00
										 |  |  | } |