[linux-dvb] AC3 support for test_av_play with firmware 0x2622

Dr. Werner Fink werner at suse.de
Thu Dec 8 14:57:36 CET 2005


Hi,

a changed version of the test_av_play of the test applications
from the dvb-apps package.  With this version also an AC3 audio
channel can be used.  Beside this some minor corrections and
enhencments were done.

--------------------------* snip *--------------------------------
--- test/test_av_play.c
+++ test/test_av_play.c	2005-12-08 09:31:46.000000000 +0100
@@ -19,27 +19,44 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
+ * Thu Jun 24 09:18:44 CEST 2004
+ *   Add scan_file_av() and copy_to_dvb() for AV
+ *   filtering to be able to use AC3 audio streams
+ *   Copyright (C) 2004 Werner Fink <werner at suse.de>
  */
 
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
 #include <sys/ioctl.h>
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <netinet/in.h>
 #include <fcntl.h>
 #include <time.h>
+#include <termios.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include <linux/dvb/dmx.h>
 #include <linux/dvb/video.h>
 #include <linux/dvb/audio.h>
 #include <sys/poll.h>
 
+static char dolby;
+static char audio;
+static char black;
+static char volset;
+
 static int audioPlay(int fd)
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,AUDIO_PLAY) < 0)){
+	if ((ans = ioctl(fd,AUDIO_PLAY)) < 0) {
 		perror("AUDIO PLAY: ");
 		return -1;
 	}
@@ -47,12 +64,11 @@
 	return 0;
 }
 
-
 static int audioSelectSource(int fd, audio_stream_source_t source)
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,AUDIO_SELECT_SOURCE, source) < 0)){
+	if ((ans = ioctl(fd,AUDIO_SELECT_SOURCE, source)) < 0) {
 		perror("AUDIO SELECT SOURCE: ");
 		return -1;
 	}
@@ -60,13 +76,11 @@
 	return 0;
 }
 
-
-
 static int audioSetMute(int fd, int state)
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,AUDIO_SET_MUTE, state) < 0)){
+	if ((ans = ioctl(fd,AUDIO_SET_MUTE, state)) < 0) {
 		perror("AUDIO SET MUTE: ");
 		return -1;
 	}
@@ -78,7 +92,7 @@
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,AUDIO_SET_AV_SYNC, state) < 0)){
+	if ((ans = ioctl(fd,AUDIO_SET_AV_SYNC, state)) < 0) {
 		perror("AUDIO SET AV SYNC: ");
 		return -1;
 	}
@@ -86,11 +100,55 @@
 	return 0;
 }
 
+static int audioSetVolume(int fd, int level)
+{
+	int ans;
+	audio_mixer_t mix;
+
+	mix.volume_left = mix.volume_right = level;
+	if ((ans = ioctl(fd, AUDIO_SET_MIXER, &mix)) < 0) {
+		perror("AUDIO SET VOLUME: ");
+		return -1;
+	}
+	return 0;
+}
+
+static int audioStop(int fd)
+{
+	int ans;
+
+	if ((ans = ioctl(fd,AUDIO_STOP,0)) < 0) {
+		perror("AUDIO STOP: ");
+		return -1;
+	}
+	return 0;
+}
+
+static int deviceClear(int afd, int vfd)
+{
+	int ans;
+
+	if (vfd >= 0) {
+		if ((ans = ioctl(vfd, VIDEO_CLEAR_BUFFER, 0)) < 0) {
+			perror("VIDEO CLEAR BUFFER: ");
+			return -1;
+		}
+	}
+	if (afd >= 0) {
+		if ((ans = ioctl(afd, AUDIO_CLEAR_BUFFER, 0)) < 0) {
+			perror("AUDIO CLEAR BUFFER: ");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 static int videoStop(int fd)
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,VIDEO_STOP,0) < 0)){
+	if ((ans = ioctl(fd,VIDEO_STOP,0)) < 0) {
 		perror("VIDEO STOP: ");
 		return -1;
 	}
@@ -102,7 +160,7 @@
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,VIDEO_PLAY) < 0)){
+	if ((ans = ioctl(fd,VIDEO_PLAY)) < 0) {
 		perror("VIDEO PLAY: ");
 		return -1;
 	}
@@ -110,12 +168,11 @@
 	return 0;
 }
 
-
 static int videoFreeze(int fd)
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,VIDEO_FREEZE) < 0)){
+	if ((ans = ioctl(fd,VIDEO_FREEZE)) < 0) {
 		perror("VIDEO FREEZE: ");
 		return -1;
 	}
@@ -123,12 +180,22 @@
 	return 0;
 }
 
+static int videoBlank(int fd, int state)
+{
+	int ans;
+
+	if ((ans = ioctl(fd, VIDEO_SET_BLANK, state)) < 0) {
+		perror("VIDEO BLANK: ");
+		return -1;
+	}
+	return 0;
+}
 
 static int videoContinue(int fd)
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,VIDEO_CONTINUE) < 0)){
+	if ((ans = ioctl(fd,VIDEO_CONTINUE)) < 0) {
 		perror("VIDEO CONTINUE: ");
 		return -1;
 	}
@@ -140,7 +207,7 @@
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,VIDEO_SELECT_SOURCE, source) < 0)){
+	if ((ans = ioctl(fd,VIDEO_SELECT_SOURCE, source)) < 0) {
 		perror("VIDEO SELECT SOURCE: ");
 		return -1;
 	}
@@ -153,7 +220,7 @@
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,VIDEO_FAST_FORWARD, nframes) < 0)){
+	if ((ans = ioctl(fd,VIDEO_FAST_FORWARD, nframes)) < 0) {
 		perror("VIDEO FAST FORWARD: ");
 		return -1;
 	}
@@ -165,7 +232,7 @@
 {
 	int ans;
 
-	if ( (ans = ioctl(fd,VIDEO_SLOWMOTION, nframes) < 0)){
+	if ((ans = ioctl(fd,VIDEO_SLOWMOTION, nframes)) < 0) {
 		perror("VIDEO SLOWMOTION: ");
 		return -1;
 	}
@@ -173,14 +240,11 @@
 	return 0;
 }
 
-#define BUFFY 32768
 #define NFD   3
-static void play_file_av(int filefd, int vfd, int afd)
+static void copy_to_dvb(int vfd, int afd, int cfd, const uint8_t* ptr, const unsigned short len)
 {
-	char buf[BUFFY];
-	int count;
-	int written;
 	struct pollfd pfd[NFD];
+	unsigned short pos = 0;
 	int stopped = 0;
 
 	pfd[0].fd = STDIN_FILENO;
@@ -192,119 +256,395 @@
 	pfd[2].fd = afd;
 	pfd[2].events = POLLOUT;
 
-	videoSelectSource(vfd,VIDEO_SOURCE_MEMORY);
-	audioSelectSource(afd,AUDIO_SOURCE_MEMORY);
-
-	// FIXME: only seems to work if starting audio first!
-	audioPlay(afd);
-	videoPlay(vfd);
-
-	count = read(filefd,buf,BUFFY);
-	write(vfd,buf,count);
-
-	while ( (count = read(filefd,buf,BUFFY)) >= 0  ){
-		written = 0;
-		while(written < count){
-			if (poll(pfd,NFD,1)){
-				if (pfd[1].revents & POLLOUT){
-					written += write(vfd,buf+written,
-							count-written);
+	while (pos < len) {
+		int ret;
+		if ((ret = poll(pfd,NFD,1)) > 0) {
+			if (pfd[1].revents & POLLOUT) {
+				int cnt = write(cfd, ptr + pos, len - pos);
+				if (cnt > 0)
+					pos += cnt;
+				else if (cnt < 0) {
+					if (errno != EAGAIN && errno != EINTR) {
+						perror("Write:");
+						exit(-1);
+					}
+					if (errno == EAGAIN)
+						usleep(1000);
+					continue;
 				}
-				if (pfd[0].revents & POLLIN){
-					int c = getchar();
-					switch(c){
-					case 'z':
+			}
+			if (pfd[0].revents & POLLIN) {
+				int c = getchar();
+				switch(c) {
+				case 'z':
+					if (audio && !black) {
+						audioSetMute(afd, 1);
+					} else {
 						videoFreeze(vfd);
-						printf("playback frozen\n");
-						stopped = 1;
-						break;
-
-					case 's':
+					}
+					deviceClear(afd, -1);
+					printf("playback frozen\n");
+					stopped = 1;
+					break;
+
+				case 's':
+					if (audio) {
+						audioStop(afd);
+						deviceClear(afd, -1);
+					} else {
 						videoStop(vfd);
-						printf("playback stopped\n");
-						stopped = 1;
-						break;
-
-					case 'c':
+						deviceClear(afd, vfd);
+					}
+					printf("playback stopped\n");
+					stopped = 1;
+					break;
+
+				case 'c':
+					if (audio && !black) {
+						audioSetAVSync(afd, 0);
+						deviceClear(afd, -1);
+						audioSetMute(afd, 0);
+					} else {
+						audioSetAVSync(afd, 1);
+						deviceClear(afd, vfd);
 						videoContinue(vfd);
-						printf("playback continued\n");
-						stopped = 0;
-						break;
-
-					case 'p':
-						videoPlay(vfd);
+					}
+					printf("playback continued\n");
+					stopped = 0;
+					break;
+
+				case 'p':
+					if (audio) {
+						deviceClear(afd, -1);
+						audioSetAVSync(afd, 0);
 						audioPlay(afd);
-					        audioSetAVSync(afd, 1);
-						audioSetMute(afd, 0);
-						printf("playback started\n");
-						stopped = 0;
-						break;
-
-					case 'f':
-					        audioSetAVSync(afd, 0);
+					} else {
+						deviceClear(afd, vfd);
+						audioSetAVSync(afd, 1);
+						audioPlay(afd);
+						videoPlay(vfd);
+					}
+					audioSetMute(afd, 0);
+					printf("playback started\n");
+					stopped = 0;
+					break;
+
+				case 'f':
+					audioSetAVSync(afd, 0);
+					if (!audio) {
 						audioSetMute(afd, 1);
 						videoFastForward(vfd,0);
-						printf("fastforward\n");
-						stopped = 0;
-						break;
-
-					case 'm':
-					        audioSetAVSync(afd, 0);
+					}
+					printf("fastforward\n");
+					stopped = 0;
+					break;
+
+				case 'm':
+					audioSetAVSync(afd, 0);
+					audioSetMute(afd, 1);
+					printf("mute\n");
+					stopped = 0;
+					break;
+
+				case 'u':
+					audioSetAVSync(afd, 1);
+					audioSetMute(afd, 0);
+					printf("unmute\n");
+					stopped = 0;
+					break;
+
+				case 'd':
+					if (dolby)
+						dolby = 0;
+					else
+						dolby++;
+					break;
+
+				case 'l':
+					audioSetAVSync(afd, 0);
+					if (!audio) {
 						audioSetMute(afd, 1);
 						videoSlowMotion(vfd,2);
-						printf("slowmotion\n");
-						stopped = 0;
-						break;
+					}
+					printf("slowmotion\n");
+					stopped = 0;
+					break;
+
+				case 'q':
+					videoContinue(vfd);
+					exit(0);
+					break;
 
-					case 'q':
-						videoContinue(vfd);
-						exit(0);
-						break;
+				default:
+					break;
+				}
+			}
+		} else if (ret < 0) {
+			if (errno != EAGAIN && errno != EINTR) {
+				perror("Write:");
+				exit(-1);
+			}
+			if (errno == EAGAIN)
+				usleep(1000);
+		}
+	}
+}
+
+static unsigned char play[6] = {0x00, 0x00, 0x01, 0xff, 0xff, 0xff};
+static unsigned char except[2];
+
+static int scan_file_av(int vfd, int afd, const unsigned char *buf, int buflen)
+{
+	const unsigned char *const start = buf;
+	const unsigned char *const   end = buf + buflen;
+
+	static unsigned int magic = 0xffffffff;
+	static unsigned short count, len;
+	static int fdc = -1;
+	int m;
+
+	while (buf < end) {
+		if (count < 6) {
+			switch (count) {
+			case 0:
+				m = 0;
+				while ((magic & 0xffffff00) != 0x00000100) {
+					if (buf >= end) goto out;
+					magic = (magic << 8) | *buf++;
+					m++;
+				}
+				if (m > 4)
+					printf("Broken Frame found\n");
+				play[3] = (unsigned char)(magic & 0x000000ff);
+				switch (play[3]) {
+				case 0xE0 ... 0xEF:
+					fdc = vfd;
+					if (except[0] != play[3]) {
+						if (except[0] == 0)
+							except[0] = play[3];
+						else
+							fdc = -1;
+					}
+					if (audio)
+						fdc = -1;
+					break;
+				case 0xC0 ... 0xDF:
+					fdc = afd;
+					if (dolby)
+						fdc = -1;
+					if (except[1] != play[3]) {
+						if (except[1] == 0)
+							except[1] = play[3];
+						else
+							fdc = -1;
 					}
+					if (!volset) {
+						audioSetVolume(afd, 255);
+						volset = 1;
+					}
+					break;
+				case 0xBD:
+					/*
+					 * TODO: sub filter to through out e.g. ub pictures
+					 * in Private Streams 1 _and_ get sub audio header
+					 * to set an except(ion) audio stream.
+					 * The later one requires some changes within the VDR
+					 * remux part!  2004/07/01 Werner
+					 */
+					fdc = afd;
+					if (!dolby)
+						fdc = -1;
+					if (volset) {
+						audioSetVolume(afd, 0);
+						volset = 0;
+					}
+					break;
+				default:
+					fdc = -1;
+					break;
 				}
+				count = 4;
+			case 4:
+				if (buf >= end) goto out;
+				len = ((*buf) << 8);
+				play[4] = (*buf);
+				buf++;
+				count++;
+			case 5:
+				if (buf >= end) goto out;
+				len |= (*buf);
+				len += 6;
+				play[5] = (*buf);
+				buf++;
+				count++;
+				if (fdc != -1)
+					copy_to_dvb(vfd, afd, fdc, &play[0], count);
+			default:
+				break;
 			}
 		}
+
+		while (count < len) {
+			int rest = end - buf;
+			if (rest <= 0) goto out;
+
+			if (rest + count > len)
+				rest = len - count;
+
+			if (fdc != -1)
+				copy_to_dvb(vfd, afd, fdc, buf, rest);
+			count += rest;
+			buf   += rest;
+		}
+
+		/* Reset for next scan */
+		magic = 0xffffffff;
+		count = len = 0;
+		fdc = -1;
+		play[3] = 0xff;
 	}
+out:
+	return buf - start;
+}
+
+#define BUFFY 32768
+static void play_file_av(int filefd, int vfd, int afd)
+{
+	char buf[BUFFY];
+	int count;
+
+	audioSetMute(afd, 1);
+	videoBlank(vfd, 1);
+	if (audio && !black) {
+		audioStop(afd);
+		deviceClear(afd, -1);
+		audioSetAVSync(afd, 0);
+		audioSelectSource(afd, AUDIO_SOURCE_MEMORY);
+		audioPlay(afd);
+		videoBlank(vfd, 0);
+	} else if (audio && black) {
+		deviceClear(afd, vfd);
+		videoBlank(vfd, 1);
+		audioSetAVSync(afd, 0);
+		audioSelectSource(afd, AUDIO_SOURCE_MEMORY);
+		videoSelectSource(vfd, VIDEO_SOURCE_MEMORY);
+		audioPlay(afd);
+		videoPlay(vfd);
+	} else {
+		deviceClear(afd, vfd);
+		audioSetAVSync(afd, 1);
+		audioSelectSource(afd, AUDIO_SOURCE_MEMORY);
+		videoSelectSource(vfd, VIDEO_SOURCE_MEMORY);
+		audioPlay(afd);
+		videoPlay(vfd);
+		videoBlank(vfd, 0);
+	}
+
+	if (dolby) {
+		audioSetVolume(afd, 0);
+		volset = 0;
+	} else {
+		audioSetVolume(afd, 255);
+		volset = 1;
+	}
+
+#ifndef __stub_posix_fadvise
+	posix_fadvise(filefd, 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
+
+	while ((count = read(filefd,buf,BUFFY)) > 0)
+		scan_file_av(vfd,afd,buf,count);
+}
+
+static struct termios term;
+
+static void restore(void)
+{
+	tcsetattr(STDIN_FILENO, TCSANOW, &term);
 }
 
 int main(int argc, char **argv)
 {
-	int vfd, afd;
+	int vfd, afd, c;
 	int filefd;
-	char *videodev = "/dev/dvb/adapter0/video0";
-	char *audiodev = "/dev/dvb/adapter0/audio0";
+	const char *videodev = "/dev/dvb/adapter0/video0";
+	const char *audiodev = "/dev/dvb/adapter0/audio0";
 
-	if (argc < 2) {
-		fprintf(stderr, "usage: test_av_play mpeg_A+V_PES_file\n");
-		return 1;
+	if (((tcgetpgrp(STDIN_FILENO) == getpid()) || (getppid() != (pid_t)1))
+	    && (tcgetattr(STDIN_FILENO, &term) == 0)) {
+		struct termios newterm;
+		memcpy(&newterm, &term, sizeof(struct termios));
+		newterm.c_iflag = 0;
+		newterm.c_lflag &= ~(ICANON | ECHO);
+		newterm.c_cc[VMIN] = 0;
+		newterm.c_cc[VTIME] = 0;
+		atexit(restore);
+		tcsetattr(STDIN_FILENO, TCSANOW, &newterm);
+	}
+
+	opterr = 0;
+	while ((c = getopt(argc, argv, "+daA")) != -1) {
+		switch (c) {
+		case 'd':
+			dolby++;
+			break;
+		case 'a':
+			audio++;
+			break;
+		case 'A':
+			audio++;
+			black++;
+			break;
+		case '?':
+			fprintf(stderr, "usage: test_av_play [-d] [-a] [-A] mpeg_A+V_PES_file\n");
+			return 1;
+		default:
+			break;
+		}
 	}
+	argv += optind;
+	argc -= optind;
 
 	if (getenv("VIDEO"))
 		videodev = getenv("VIDEO");
 	if (getenv("AUDIO"))
-		videodev = getenv("AUDIO");
+		audiodev = getenv("AUDIO");
 
 	printf("using video device '%s'\n", videodev);
 	printf("using audio device '%s'\n", audiodev);
 
-	if ( (filefd = open(argv[1],O_RDONLY)) < 0){
+	putchar('\n');
+
+	printf("Freeze       by pressing `z'\n");
+	printf("Stop         by pressing `s'\n");
+	printf("Continue     by pressing `c'\n");
+	printf("Start        by pressing `p'\n");
+	printf("FastForward  by pressing `f'\n");
+	printf("Mute         by pressing `m'\n");
+	printf("UnMute       by pressing `u'\n");
+	printf("MP2/AC3      by pressing `d'\n");
+	printf("SlowMotion   by pressing `l'\n");
+	printf("Quit         by pressing `q'\n");
+
+	putchar('\n');
+
+	errno = ENOENT;
+	if (!argv[0] || (filefd = open(argv[0], O_RDONLY)) < 0) {
 		perror("File open:");
 		return -1;
 	}
-	if ((vfd = open(videodev,O_RDWR|O_NONBLOCK)) < 0){
+	if ((vfd = open(videodev,O_RDWR|O_NONBLOCK)) < 0) {
 		perror("VIDEO DEVICE: ");
 		return -1;
 	}
-	if ((afd = open(audiodev,O_RDWR|O_NONBLOCK)) < 0){
+	if ((afd = open(audiodev,O_RDWR|O_NONBLOCK)) < 0) {
 		perror("AUDIO DEVICE: ");
 		return -1;
 	}
+
 	play_file_av(filefd, vfd, afd);
 	close(vfd);
 	close(afd);
 	close(filefd);
 	return 0;
-
-
 }
-
--------------------------* snap *--------------------------------

Just to be able to test the new feature of the firmware 0x2622
without using VDR.


       Werner

-- 
AC3 loop through sound card http://bitstreamout.sourceforge.net/
Howto http://www.vdr-portal.de/board/thread.php?threadid=1958
------------------------------------------------------------------
 "Having a smoking section in a restaurant is like having
         a  peeing section in a swimming pool." -- Edward Burr



More information about the linux-dvb mailing list