View Single Post
Old 07-13-2012, 11:29 PM   #141
( ͡° ͜ʖ ͡°){ʇlnɐɟ ƃǝs}Týr
twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.twobob ought to be getting tired of karma fortunes by now.
twobob's Avatar
Posts: 6,491
Karma: 5977000
Join Date: Jun 2012
Location: uti gratia usura (Yao ying da ying; Mo ying da yieng)
Device: PW-WIFI|K5-3G+WIFI| K4|K3-3G|DXG|K2| Rooted Nook Touch
zcat santa.raw.gz |./Balsamic plughw:0 ./santa8kmono.wav

This doesn't actually work by the way. video is miles out of sync (I only scoop every 4 frames right now while I get it going) - also don't want the separate files - or separate inputs - or to run to mem - and various other bad things.

EDIT: I Added threading, The video is MILES out of sync but is pictures and sound.
And now not so jerky, Proof of utterly mangled concept, A true coding horror but with a little massage and some process unification I think this will get the job done.

the principle of seperate files is fundamentally flawed (as I knew it would be) but I wanted sound and vision and I got it. Time to tidy up the file handling and unify the data stream

#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include <asoundlib.h>
#include <math.h>
#include <pthread.h>

// gmplay 1.5a - geekmaster's kindle video player
// Copyright (C) 2012 by geekmaster, with MIT license:
// Tested on DX,DXG,K3,K4main,K4diags,K5main,K5diags.
#include <sys/ioctl.h>     // ioctl
#include <sys/mman.h>     // mmap, munmap
#include <stdio.h>       // printf
#include <stdlib.h>     // malloc, free
#include <linux/fb.h>  // screeninfo
#include <sys/time.h> // gettimeofday
#include <unistd.h>  // usleep
#include <string.h> // memset, memcpy
#include <fcntl.h> // open, close, write
#include <time.h> // time
typedef unsigned long u64;
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
u32 __invalid_size_argument_for_IOC; // ioctl.h bug fix for tcc
//----- eink definitions from eink_fb.h and mxcfb.h -----
#define EU3 0x46dd
#define EU50 0x4040462e
#define EU51 0x4048462e
#define NUM_THREADS 3
struct update_area_t {int x1,y1,x2,y2,which_fx;u8 *buffer;};
struct mxcfb_rect {u32 top,left,width,height;};
struct mxcfb_alt_buffer_data {u32 phys_addr,width,height;
struct mxcfb_rect alt_update_region;};
struct mxcfb_update_data {struct mxcfb_rect update_region;
u32 waveform_mode,update_mode,update_marker;int temp;uint flags;
struct mxcfb_alt_buffer_data alt_buffer_data;};
struct mxcfb_update_data51 {struct mxcfb_rect update_region;
u32 waveform_mode,update_mode,update_marker;
u32 hist_bw_waveform_mode,hist_gray_waveform_mode;
int temp;uint flags;struct mxcfb_alt_buffer_data alt_buffer_data;};
//----- function prototypes -----
void gmplay4(void);
//void gmplay8(void);
int getmsec(void);
int gmlib(int);
//----- gmlib global vars -----
u8 *fb0=NULL;     // framebuffer pointer
int fdFB=0;      // fb0 file descriptor
int teu=0;      // eink update time
u32 fs=0;      // fb0 stride
u32 MX=0;     // xres (visible)
u32 MY=0;    // yres (visible)
u32 VY=0;   // (VY>MY): mxcfb driver
u8 ppb=0;  // pixels per byte
u32 fc=0; // frame counter
#define FBSIZE (600/8*800)

// gmlib - geekmaster function library
// op (init, update, vsync, close)
int gmlib(int op) {
	static struct update_area_t ua={0,0,600,800,21,NULL};
	static struct mxcfb_update_data ur={
	static struct mxcfb_update_data51 ur51={
	static int eupcode; static void *eupdata=NULL;
	struct fb_var_screeninfo screeninfo;
	if (GMLIB_INIT==op) { teu=getmsec(); fdFB=open("/dev/fb0",O_RDWR);
	ppb=8/screeninfo.bits_per_pixel; fs=screeninfo.xres_virtual/ppb;
	VY=screeninfo.yres_virtual; MX=screeninfo.xres; MY=screeninfo.yres;
	ua.x2=MX; ua.y2=MY; ur.update_region.width=MX; ur.update_region.height=MY;
	fb0=(u8 *)mmap(0,MY*fs,PROT_READ|PROT_WRITE,MAP_SHARED,fdFB,0); // map fb0
	if (VY>MY) { eupcode=EU50; eupdata=&ur; ur.update_mode=0;
	if (ioctl(fdFB,eupcode,eupdata)<0) { eupcode=EU51; eupdata=&ur51; }
	} else { eupcode=EU3; eupdata=&ua; }
	system("eips -f -c;eips -c"); sleep(1);
	} else if (GMLIB_UPDATE==op) {
		if (ioctl(fdFB,eupcode,eupdata)<0) system("eips ''");  // 5.1.0 fallback
	} else if (GMLIB_VSYNC==op) { while (teu>getmsec()) usleep(1000); // fb0 busy
	} else if (GMLIB_CLOSE==op) { gmlib(GMLIB_UPDATE); sleep(1); // last screen
	system("eips -f -c;eips -c"); munmap(fb0,MY*fs); close(fdFB);
	} else { return -1; }
	return 0;
// getmsec - get msec since first call
// (tick counter wraps every 12 days)
int getmsec(void) {
	int tc; static int ts=0; struct timeval tv;
	gettimeofday(&tv,NULL); tc=tv.tv_usec/1000+1000*(0xFFFFF&tv.tv_sec);
	if (0==ts) ts=tc;
	return tc-ts;

// Points to loaded WAVE file's data
unsigned char			*WavePtr;

// Size (in frames) of loaded WAVE file's data
snd_pcm_uframes_t		WaveSize;

// Sample rate
unsigned short			WaveRate;

// Bit resolution
unsigned char			WaveBits;

// Number of channels in the wave file
unsigned char			WaveChannels;

// For WAVE file loading
static const unsigned char Riff[4]	= { 'R', 'I', 'F', 'F' };
static const unsigned char Wave[4] = { 'W', 'A', 'V', 'E' };
static const unsigned char Fmt[4] = { 'f', 'm', 't', ' ' };
static const unsigned char Data[4] = { 'd', 'a', 't', 'a' };

snd_pcm_t *playback_handle;

unsigned int i,j;
int playcount;
int indexer;
int err;

// gmplay4 - play video on 4-bit fb0
void gmplay4(void) {

	// We should scoop info from the unified file - and possibly via an indirect buffer.
	// Time indexing lookup - perhaps via a mutex provsioned RO value might be an idea
	// They are both TODO

	u32 i,x,y,b,p,off=(MY/2-400)*fs+MX/4-150,fbsize=FBSIZE; u8 fbt[FBSIZE];
	while (fread(fbt,fbsize,1,stdin)) { teu+=130; // teu: next update time
	if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind
	// gmlib(GMLIB_VSYNC); // wait for fb0 ready
	for (y=0;y<800;y++) for (x=0;x<600;x+=8) {
		b=fbt[600/8*y+x/8]; i=y*fs+x/2+off;
		p=(b&1)*240; b>>=1; fb0[i]=p|(b&1)*15; b>>=1;
		p=(b&1)*240; b>>=1; fb0[i+1]=p|(b&1)*15; b>>=1;
		p=(b&1)*240; b>>=1; fb0[i+2]=p|(b&1)*15; b>>=1;
		p=(b&1)*240; b>>=1; fb0[i+3]=p|(b&1)*15;
	} fc++; gmlib(GMLIB_UPDATE);

	//   printf("did this");

playback_callback (snd_pcm_sframes_t nframes)

	indexer = (4096*(playcount*2));

	if ((err = snd_pcm_writei (playback_handle, WavePtr+indexer, nframes)) < 0) {
		fprintf (stderr, "write failed (%s)\n", snd_strerror (err));
	return err;


#pragma pack (1)
/////////////////////// WAVE File Stuff /////////////////////
// An IFF file header looks like this
typedef struct _FILE_head
	unsigned char	ID[4];
	// could be {'R', 'I', 'F', 'F'} or {'F', 'O', 'R', 'M'}
	unsigned int	Length;
	// Length of subsequent file (including remainder of header).
	//This is in Intel reverse byte order if RIFF, Motorola format if FORM.
	unsigned char	Type[4];
	// {'W', 'A', 'V', 'E'} or {'A', 'I', 'F', 'F'}
} FILE_head;

// An IFF chunk header looks like this
typedef struct _CHUNK_head
	unsigned char ID[4];	// 4 ascii chars that is the chunk ID
	unsigned int	Length;	// Length of subsequent data within this chunk. This is in Intel reverse byte
	// order if RIFF, Motorola format if FORM. Note: this doesn't include any
	// extra byte needed to pad the chunk out to an even size.
} CHUNK_head;

// WAVE fmt chunk
typedef struct _FORMAT {
	short				wFormatTag;
	unsigned short	wChannels;
	unsigned int	dwSamplesPerSec;
	unsigned int	dwAvgBytesPerSec;
	unsigned short	wBlockAlign;
	unsigned short	wBitsPerSample;
	// Note: there may be additional fields here, depending upon wFormatTag
#pragma pack()

/********************** compareID() *********************
 * Compares the passed ID str (ie, a ptr to 4 Ascii
 * bytes) with the ID at the passed ptr. Returns TRUE if
 * a match, FALSE if not.

static unsigned char compareID(const unsigned char * id, unsigned char * ptr)
	register unsigned char i = 4;

	while (i--)
		if ( *(id)++ != *(ptr)++ ) return(0);

/********************** waveLoad() *********************
 * Loads a WAVE file.
 * fn =			Filename to load.
 * RETURNS: 0 if success, non-zero if not.
 * NOTE: Sets the global "WavePtr" to an allocated buffer
 * containing the wave data, and "WaveSize" to the size
 * in sample points.


static unsigned char waveLoad(const char *fn)
	const char				*message;
	FILE_head				head;
	register int			inHandle;

	if ((inHandle = open(fn, O_RDONLY)) == -1)
		message = "didn't open";

	// Read in IFF File header
		if (read(inHandle, &head, sizeof(FILE_head)) == sizeof(FILE_head))
			// Is it a RIFF and WAVE?
			if (!compareID(&Riff[0], &head.ID[0]) || !compareID(&Wave[0], &head.Type[0]))
				message = "is not a WAVE file";
				goto bad;

			// Read in next chunk header
			while (read(inHandle, &head, sizeof(CHUNK_head)) == sizeof(CHUNK_head))
				// ============================ Is it a fmt chunk? ===============================
				if (compareID(&Fmt[0], &head.ID[0]))
					FORMAT	format;

					// Read in the remainder of chunk
					if (read(inHandle, &format.wFormatTag, sizeof(FORMAT)) != sizeof(FORMAT)) break;

					// Can't handle compressed WAVE files
					if (format.wFormatTag != 1)
						message = "compressed WAVE not supported";
						goto bad;

					WaveBits = (unsigned char)format.wBitsPerSample;
					WaveRate = (unsigned short)format.dwSamplesPerSec;
					WaveChannels = format.wChannels;

				// ============================ Is it a data chunk? ===============================
				else if (compareID(&Data[0], &head.ID[0]))
					// Size of wave data is head.Length. Allocate a buffer and read in the wave data
					if (!(WavePtr = (unsigned char *)malloc(head.Length)))
						message = "won't fit in RAM";
						goto bad;

					if (read(inHandle, WavePtr, head.Length) != head.Length)

					// Store size (in frames)
					WaveSize = (head.Length * 8) / ((unsigned int)WaveBits * (unsigned int)WaveChannels);


				// ============================ Skip this chunk ===============================
					if (head.Length & 1) ++head.Length;  // If odd, round it up to account for pad byte
					lseek(inHandle, head.Length, SEEK_CUR);

		message = "is a bad WAVE file";
		bad:	close(inHandle);

	printf("%s %s\n", fn, message);

/*********************** free_wave_data() *********************
 * Frees any wave data we loaded.
 * NOTE: A pointer to the wave data be in the global
 * "WavePtr".

static void free_wave_data(void)
	if (WavePtr) free(WavePtr);
	WavePtr = 0;

// Showtime

main (int argc, char *argv[])

	int i;

	char *wavename = argv[2];

	if (!waveLoad(wavename))
		register int		err;

		printf("Loaded: %s\n", wavename);


	snd_pcm_hw_params_t *hw_params;
	snd_pcm_sw_params_t *sw_params;
	snd_pcm_sframes_t frames_to_deliver;
	int nfds;
	int err;
	struct pollfd *pfds;

	if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
		fprintf (stderr, "cannot open audio device %s (%s)\n",
				snd_strerror (err));
		exit (1);

	if ((err = snd_pcm_set_params(playback_handle,
			900000)) < 0) {   /* 0.5sec */
		printf("Playback open error: %s\n", snd_strerror(err));

	/* tell ALSA to wake us up whenever 4096 or more frames
		   of playback data can be delivered. Also, tell
		   ALSA that we'll start the device ourselves.

	if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) {
		fprintf (stderr, "cannot allocate software parameters structure (%s)\n",
				snd_strerror (err));
		exit (1);
	if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0) {
		fprintf (stderr, "cannot initialize software parameters structure (%s)\n",
				snd_strerror (err));
		exit (1);
	if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 4096)) < 0) {
		fprintf (stderr, "cannot set minimum available count (%s)\n",
				snd_strerror (err));
		exit (1);
	if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 0U)) < 0) {
		fprintf (stderr, "cannot set start mode (%s)\n",
				snd_strerror (err));
		exit (1);
	if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0) {
		fprintf (stderr, "cannot set software parameters (%s)\n",
				snd_strerror (err));
		exit (1);

	/* the interface will interrupt the kernel every 4096 frames, and ALSA
		   will wake up this program very soon after that.

	if ((err = snd_pcm_prepare (playback_handle)) < 0) {
		fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
				snd_strerror (err));
		exit (1);


	pthread_t threads[NUM_THREADS];
	int rc;
	long t;


	// Make a thread

	printf("In main: creating thread %ld\n", t);
	char *message1 = "Video Thread";

	// This is the thread.

	rc = pthread_create(&threads[t], NULL, gmplay4, (void*) message1);

	if (rc){
		printf("ERROR; return code from pthread_create() is %d\n", rc);
		i=getmsec()/100; printf("%d frames in %0.1f secs = %2.1f FPS\n",


	while (1) {


		// We should create a buffer area to scoop audio into from the main feed -
		// as audio is bloody picky about actually playing
		// it would be nice to consider some type of time indexing for this I guess to give us a sense of info unity.

		/* wait till the interface is ready for data, or 1 second
			   has elapsed.

		if ((err = snd_pcm_wait (playback_handle, 1000)) < 0) {
			fprintf (stderr, "poll failed (%s)\n", strerror (errno));

		/* find out how much space is available for playback data */

		if ((frames_to_deliver = snd_pcm_avail_update (playback_handle)) < 0) {
			if (frames_to_deliver == -EPIPE) {
				fprintf (stderr, "an xrun occured\n");
			} else {
				fprintf (stderr, "unknown ALSA avail update return value (%d)\n",

		if (	frames_to_deliver > 4096 ){ frames_to_deliver = 4096;}

		/* deliver the data */

		if (playback_callback (frames_to_deliver) != frames_to_deliver) {
			fprintf (stderr, "playback callback failed\n");
	i=getmsec()/100; printf("%d frames in %0.1f secs = %2.1f FPS\n",
	snd_pcm_close (playback_handle);
	exit (0);

Tomorrows job - make this actually work at all heheheh still sound and video together is always good, however mangled and wrong

It's the future.

Last edited by twobob; 07-14-2012 at 10:37 AM. Reason: added call structure, and some sense - and partial success
twobob is offline   Reply With Quote