( ͡° ͜ʖ ͡°){ʇlnɐɟ ƃǝs}Týr
Posts: 6,586
Karma: 6299991
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
Spoiler:
Code:
#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include <asoundlib.h>
#include <math.h>
#include <pthread.h>
// HEAD WELD
//====================================================
// gmplay 1.5a - geekmaster's kindle video player
// Copyright (C) 2012 by geekmaster, with MIT license:
// http://www.opensource.org/licenses/mit-license.php
//----------------------------------------------------
// 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 -----
enum GMLIB_op {GMLIB_INIT,GMLIB_CLOSE,GMLIB_UPDATE,GMLIB_VSYNC};
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={
{0,0,600,800},257,0,1,0x1001,0,{0,0,0,{0,0,0,0}}};
static struct mxcfb_update_data51 ur51={
{0,0,600,800},257,0,1,0,0,0x1001,0,{0,0,0,{0,0,0,0}}};
static int eupcode; static void *eupdata=NULL;
struct fb_var_screeninfo screeninfo;
if (GMLIB_INIT==op) { teu=getmsec(); fdFB=open("/dev/fb0",O_RDWR);
ioctl(fdFB,FBIOGET_VSCREENINFO,&screeninfo);
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");
}
}
int
playback_callback (snd_pcm_sframes_t nframes)
{
playcount++;
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
} FORMAT;
#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);
}
return(1);
}
/********************** 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.
*/
// END WELD
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
else
{
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)
{
free(WavePtr);
break;
}
// Store size (in frames)
WaveSize = (head.Length * 8) / ((unsigned int)WaveBits * (unsigned int)WaveChannels);
close(inHandle);
return(0);
}
// ============================ Skip this chunk ===============================
else
{
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);
return(1);
}
/*********************** 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;
gmlib(GMLIB_INIT);
char *wavename = argv[2];
if (!waveLoad(wavename))
{
register int err;
}
else
{
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",
argv[1],
snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_set_params(playback_handle,
SND_PCM_FORMAT_S16_LE,
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
8000,
0,
900000)) < 0) { /* 0.5sec */
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
/* 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);
}
// SETUP THE SCREEN
pthread_t threads[NUM_THREADS];
int rc;
long t;
gmlib(GMLIB_INIT);
// 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);
exit(-1);
i=getmsec()/100; printf("%d frames in %0.1f secs = %2.1f FPS\n",
fc,(double)i/10.0,(double)fc*10.0/i);
gmlib(GMLIB_CLOSE);
}
while (1) {
// HERE IS OUR UPDATE LOOP SEED
// 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));
break;
}
/* 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");
break;
} else {
fprintf (stderr, "unknown ALSA avail update return value (%d)\n",
frames_to_deliver);
break;
}
}
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");
break;
}
}
i=getmsec()/100; printf("%d frames in %0.1f secs = %2.1f FPS\n",
fc,(double)i/10.0,(double)fc*10.0/i);
gmlib(GMLIB_CLOSE);
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
|