4 #include <alsa/asoundlib.h>
9 const double nudge = 3.5;
10 const double ahead = .5;
13 #include "libzmpeg3.h"
15 #include "../libmpeg3/libmpeg3.h"
16 #define zmpeg3_t mpeg3_t
21 /* alpha currently is broken in gdk */
22 /* would render faster if alpha worked correctly */
28 #define COLOR_MODEL zmpeg3_t::cmdl_RGBA8888
30 #define COLOR_MODEL MPEG3_RGBA8888
36 #define COLOR_MODEL zmpeg3_t::cmdl_RGB888
38 #define COLOR_MODEL MPEG3_RGB888
46 static int verbose = 0;
48 /* c++ `pkg-config --cflags --libs gtk+-2.0` y.C ./x86_64/libzmpeg3.a -lpthread -lasound -lm -lX11 */
52 snd_pcm_uframes_t zpcm_ufrm_size = 0;
53 snd_pcm_sframes_t zpcm_sbfr_size = 0;
54 snd_pcm_sframes_t zpcm_sper_size = 0;
55 snd_pcm_sframes_t zpcm_total_samples = 0;
56 double zpcm_play_time = 0.;
57 pthread_mutex_t zpcm_lock;
58 unsigned int zpcm_rate = 0;
59 static const char *zpcm_device = "plughw:0,0";
60 static unsigned int zpcm_bfr_time_us = 500000;
61 static unsigned int zpcm_per_time_us = 200000;
62 static snd_pcm_channel_area_t *zpcm_areas = 0;
63 static int zpcm_channels = 0;
64 static short **zpcm_buffers = 0;
65 static short *zpcm_samples = 0;
70 if( zpcm_buffers != 0 ) { delete [] zpcm_buffers; zpcm_buffers = 0; }
71 if( zpcm_areas != 0 ) { delete [] zpcm_areas; zpcm_areas = 0; }
72 if( zpcm_samples != 0 ) { delete [] zpcm_samples; zpcm_samples = 0; }
74 if( zpcm_buffers != 0 ) { free(zpcm_buffers); zpcm_buffers = 0; }
75 if( zpcm_areas != 0 ) { free(zpcm_areas); zpcm_areas = 0; }
76 if( zpcm_samples != 0 ) { free(zpcm_samples); zpcm_samples = 0; }
78 if( zpcm != 0 ) { snd_pcm_close(zpcm); zpcm = 0; }
79 pthread_mutex_destroy(&zpcm_lock);
82 void alsa_open(int chs,int rate)
84 int ich, bits, byts, dir, ret;
85 pthread_mutex_init(&zpcm_lock,0);
86 snd_pcm_format_t fmt = SND_PCM_FORMAT_S16;
87 snd_pcm_hw_params_t *phw;
88 snd_pcm_sw_params_t *psw;
89 snd_pcm_hw_params_alloca(&phw);
90 snd_pcm_sw_params_alloca(&psw);
93 zpcm_total_samples = 0;
95 ret = snd_pcm_open(&zpcm, zpcm_device,
96 SND_PCM_STREAM_PLAYBACK, 0 /* + SND_PCM_NONBLOCK */);
98 ret = snd_pcm_hw_params_any(zpcm, phw);
100 ret = snd_pcm_hw_params_set_rate_resample(zpcm, phw, 1);
102 ret = snd_pcm_hw_params_set_access(zpcm, phw,
103 SND_PCM_ACCESS_RW_NONINTERLEAVED);
105 ret = snd_pcm_hw_params_set_format(zpcm, phw, fmt);
108 ret = snd_pcm_hw_params_set_channels(zpcm, phw, chs);
112 ret = snd_pcm_hw_params_set_rate_near(zpcm, phw, &zpcm_rate, 0);
113 if( (int)zpcm_rate != rate )
114 printf("nearest audio_rate for %d is %u\n",rate,zpcm_rate);
117 ret = snd_pcm_hw_params_set_buffer_time_near(zpcm, phw,
118 &zpcm_bfr_time_us, &dir);
120 ret = snd_pcm_hw_params_get_buffer_size(phw, &zpcm_ufrm_size);
122 zpcm_sbfr_size = zpcm_ufrm_size;
123 ret = snd_pcm_hw_params_set_period_time_near(zpcm, phw,
124 &zpcm_per_time_us, &dir);
127 ret = snd_pcm_hw_params_get_period_size(phw, &zpcm_ufrm_size, &dir);
129 zpcm_sper_size = zpcm_ufrm_size;
130 ret = snd_pcm_hw_params(zpcm, phw);
133 ret = snd_pcm_sw_params_current(zpcm, psw);
135 ret = snd_pcm_sw_params_set_start_threshold(zpcm, psw,
136 (zpcm_sbfr_size / zpcm_sper_size) * zpcm_sper_size);
138 ret = snd_pcm_sw_params_set_avail_min(zpcm, psw, zpcm_sper_size);
140 ret = snd_pcm_sw_params(zpcm, psw);
141 /* snd_pcm_dump(zpcm, stdout); */
145 zpcm_areas = new snd_pcm_channel_area_t[chs];
146 byts = snd_pcm_format_physical_width(fmt) / 8;
147 zpcm_samples = new short[zpcm_sper_size * chs * byts/2];
148 zpcm_buffers = new short *[chs];
150 zpcm_areas = calloc(chs, sizeof(snd_pcm_channel_area_t));
151 bits = snd_pcm_format_physical_width(fmt);
153 zpcm_samples = malloc(zpcm_sper_size * chs * byts);
154 zpcm_buffers = malloc(chs * sizeof(short*));
157 for( ich = 0; ich < chs; ++ich ) {
158 zpcm_areas[ich].addr = zpcm_samples;
159 zpcm_areas[ich].first = ich * zpcm_sper_size * bits;
160 zpcm_areas[ich].step = bits;
161 zpcm_buffers[ich] = zpcm_samples + ich*zpcm_sper_size;
165 fprintf(stderr,"alsa sample buffer allocation failure.\n");
171 printf("audio error: %s\n", snd_strerror(ret));
176 short *alsa_bfr(int ch)
178 return zpcm_buffers[ch];
183 return zpcm_sper_size;
186 int alsa_recovery(int ret)
188 printf("alsa recovery\n");
191 /* wait until the suspend flag is released, then fall through */
192 while( (ret=snd_pcm_resume(zpcm)) == -EAGAIN ) usleep(100000);
194 ret = snd_pcm_prepare(zpcm);
196 printf("underrun, prepare failed: %s\n", snd_strerror(ret));
199 printf("unhandled error: %s\n",snd_strerror(ret));
205 int alsa_write(int length)
208 int i, ret, count, retry;
209 snd_pcm_sframes_t sample_delay;
210 double play_time, time;
212 short *bfrs[zpcm_channels];
214 short **bfrs = alloca(zpcm_channels*sizeof(short *));
218 for( i=0; i<zpcm_channels; ++i ) bfrs[i] = zpcm_buffers[i];
220 while( count < length ) {
221 ret = snd_pcm_writen(zpcm,(void **)bfrs, length-count);
222 if( ret == -EAGAIN ) continue;
224 if( --retry < 0 ) return ret;
229 for( i=0; i<zpcm_channels; ++i ) bfrs[i] += ret;
232 pthread_mutex_lock(&zpcm_lock);
233 zpcm_total_samples += count;
234 snd_pcm_delay(zpcm,&sample_delay);
235 if( sample_delay > zpcm_total_samples )
236 sample_delay = zpcm_total_samples;
237 gettimeofday(&tv,NULL);
238 time = tv.tv_sec + tv.tv_usec/1000000.0;
239 play_time = (zpcm_total_samples - sample_delay) / (double)zpcm_rate;
240 zpcm_play_time = time - play_time;
241 pthread_mutex_unlock(&zpcm_lock);
242 return ret < 0 ? ret : 0;
247 double time, play_time;
249 pthread_mutex_lock(&zpcm_lock);
250 gettimeofday(&tv,NULL);
251 time = tv.tv_sec + tv.tv_usec/1000000.0;
252 play_time = time - zpcm_play_time;
253 pthread_mutex_unlock(&zpcm_lock);
261 double time, play_time;
263 gettimeofday(&tv,NULL);
264 time = tv.tv_sec + tv.tv_usec/1000000.0;
278 void dst_exit(GtkWidget *widget, gpointer data)
289 gettimeofday(&tv,NULL);
290 time = tv.tv_sec + tv.tv_usec/1000000.0;
291 if( tstart < 0. ) tstart = time;
292 return time - tstart;
296 void mpeg3_stats(zmpeg3_t *zsrc)
298 int astream, vstream;
299 int has_audio, total_astreams, audio_channels, sample_rate;
300 int has_video, total_vstreams, width, height, colormodel;
301 long audio_samples, video_frames;
304 has_audio = mpeg3_has_audio(zsrc);
305 printf(" has_audio = %d\n", has_audio);
306 total_astreams = mpeg3_total_astreams(zsrc);
307 printf(" total_astreams = %d\n", total_astreams);
308 for( astream=0; astream<total_astreams; ++astream ) {
309 audio_channels = mpeg3_audio_channels(zsrc, astream);
310 printf(" audio_channels = %d\n", audio_channels);
311 sample_rate = mpeg3_sample_rate(zsrc, astream);
312 printf(" sample_rate = %d\n", sample_rate);
313 audio_samples = mpeg3_audio_samples(zsrc, astream);
314 printf(" audio_samples = %ld\n", audio_samples);
317 has_video = mpeg3_has_video(zsrc);
318 printf(" has_video = %d\n", has_video);
319 total_vstreams = mpeg3_total_vstreams(zsrc);
320 printf(" total_vstreams = %d\n", total_vstreams);
321 for( vstream=0; vstream<total_vstreams; ++vstream ) {
322 width = mpeg3_video_width(zsrc, vstream);
323 printf(" video_width = %d\n", width);
324 height = mpeg3_video_height(zsrc, vstream);
325 printf(" video_height = %d\n", height);
326 frame_rate = mpeg3_frame_rate(zsrc, vstream);
327 printf(" frame_rate = %f\n", frame_rate);
328 video_frames = mpeg3_video_frames(zsrc, vstream);
329 printf(" video_frames = %ld\n", video_frames);
330 colormodel = mpeg3_colormodel(zsrc, vstream);
331 printf(" colormodel = %d\n", colormodel);
339 double video_time(zmpeg3_t *zsrc,int stream)
342 double vtime = mpeg3_get_video_time(zsrc,stream);
344 double vtime = mpeg3_get_time(zsrc);
347 if( vstart == 0. ) vstart = vnow;
348 if( vtime < last_vtime )
349 vstart -= last_vtime;
351 return vnow - vstart + nudge;
356 void *video_thread(void *the_zsrc)
359 GtkWidget *panel_hbox;
361 GdkPixbuf *pbuf0, *pbuf1;
362 GdkImage *img0, *img1;
365 float frame_rate, frame_delay;
366 unsigned char **rows, **row0, **row1, *cap, *cap0, *cap1;
367 int ret, row, frame, dropped, more_data;
368 int width, height, owidth, oheight;
369 const int frame_drop = 0;
370 zmpeg3_t *zsrc = (zmpeg3_t *)the_zsrc;
372 frame_rate = mpeg3_frame_rate(zsrc, 0);
373 frame_delay = 2.0 / frame_rate;
374 height = mpeg3_video_height(zsrc, 0);
375 width = mpeg3_video_width(zsrc, 0);
376 //oheight = 2*height / 3;
377 //owidth = 2*width / 3;
385 visual = gdk_visual_get_system();
386 /* toplevel window */
387 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
388 gtk_signal_connect(GTK_OBJECT(window),"destroy",
389 GTK_SIGNAL_FUNC(dst_exit),NULL);
390 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
391 /* try for shared image bfr, only seems to work with gtk_rgb */
392 img0 = gdk_image_new(GDK_IMAGE_SHARED, visual, owidth, oheight);
393 pbuf0 = gdk_pixbuf_new_from_data((const guchar *)img0->mem,
394 GDK_COLORSPACE_RGB,RGBA,8,owidth,oheight,owidth*BPP,NULL,NULL);
395 cap0 = gdk_pixbuf_get_pixels(pbuf0);
396 image = gtk_image_new_from_pixbuf(pbuf0);
397 /* double buffered */
398 img1 = gdk_image_new(GDK_IMAGE_SHARED, visual, owidth, oheight);
399 pbuf1 = gdk_pixbuf_new_from_data((const guchar *)img1->mem,
400 GDK_COLORSPACE_RGB,RGBA,8,owidth,oheight,owidth*BPP,NULL,NULL);
401 cap1 = gdk_pixbuf_get_pixels(pbuf1);
403 panel_hbox = gtk_hbox_new(FALSE,0);
404 gtk_container_add(GTK_CONTAINER(window), panel_hbox);
405 /* pack image into panel */
406 gtk_box_pack_start(GTK_BOX(panel_hbox), image, TRUE, TRUE, 0);
410 row0 = new unsigned char *[oheight];
411 row1 = new unsigned char *[oheight];
412 int cmdl = COLOR_MODEL;
414 row0 = malloc(oheight*sizeof(unsigned char *));
415 row1 = malloc(oheight*sizeof(unsigned char *));
416 int cmdl = COLOR_MODEL;
418 for( row=0; row<oheight; ++row ) {
419 row0[row] = cap0 + row*owidth*BPP;
420 row1[row] = cap1 + row*owidth*BPP;
423 gtk_widget_show_all(window);
427 vstart = last_vtime = 0.;
430 while( done == 0 && more_data ) {
431 if( !gtk_events_pending() ) {
433 delay = (frame+dropped)/frame_rate - alsa_time();
434 // delay = the_time() - video_time(zsrc,0);
436 if( -delay >= frame_delay ) {
437 int nframes = (long)ceil(-delay/frame_rate);
438 if( nframes > 2 ) nframes = 2;
439 mpeg3_drop_frames(zsrc,nframes,0);
444 usleep((int)(delay*1000000.0));
445 ret = mpeg3_read_frame(zsrc, rows, 0, 0, width, height,
446 owidth, oheight, cmdl, 0);
447 //printf("%d %ld\n",frame,zsrc->vtrack[0]->demuxer->titles[0]->fs->current_byte);
449 printf("read_video(stream=%d, frame=%d) = %d\n", 0, frame, ret);
450 //if( frame > 500 && frame < 800 ) {
451 // mpeg3_previous_frame(zsrc,0);
452 // mpeg3_previous_frame(zsrc,0);
454 GdkGC *blk = image->style->black_gc;
455 gdk_draw_rgb_image(image->window,blk, 0,0,owidth,oheight,
456 GDK_RGB_DITHER_NONE,cap,owidth*BPP);
460 { static FILE *fp = 0;
461 int sz = owidth*oheight*BPP;
462 if( fp == 0 ) fp = fopen("/tmp/dat.raw","w");
466 { static FILE *fp = 0;
467 int z, sz = owidth*oheight*BPP;
469 if( fp == 0 ) fp = fopen("/tmp/dat.raw","r");
471 for( z=0; z<sz && abs(zbfr[z]-cap[z])<=1; ++z );
472 //for( z=0; z<sz && zbfr[z]==cap[z]; ++z );
474 printf("bug %d\n",z);
477 if( frame > 250 ) exit(0);
479 *(unsigned long *)&cap ^= ((unsigned long)cap0 ^ (unsigned long)cap1);
480 *(unsigned long *)&rows ^= ((unsigned long)row0 ^ (unsigned long)row1);
481 //printf(" %d/%d %f %f %f\n",frame,dropped,(frame+dropped)/frame_rate,
482 // video_time(zsrc,0),mpeg3_get_video_time(zsrc,0));
484 more_data |= !mpeg3_end_of_video(zsrc,0);
487 gtk_main_iteration();
498 double audio_time(zmpeg3_t *zsrc, int stream)
501 double anow = mpeg3_get_audio_time(zsrc,stream);
503 double anow = mpeg3_get_time(zsrc);
505 if( astart < 0. ) astart = anow;
506 return anow - astart;
511 void *audio_thread(void *the_zsrc)
514 int audio_channels, sample_rate, more_data;
515 zmpeg3_t *zsrc = (zmpeg3_t *)the_zsrc;
518 audio_channels = mpeg3_audio_channels(zsrc, stream);
519 sample_rate = mpeg3_sample_rate(zsrc, stream);
520 alsa_open(audio_channels,sample_rate);
524 while( done == 0 && more_data ) {
527 int n = alsa_bfrsz();
528 for( ich=0; ich<audio_channels; ++ich) {
529 short *bfr = alsa_bfr(ich);
531 mpeg3_read_audio(zsrc, 0, bfr, ich, n, stream) :
532 mpeg3_reread_audio(zsrc, 0, bfr, ich, n, stream);
534 printf("read_audio(stream=%d,channel=%d) = %d\n", stream, ich, ret);
538 delay = audio_time(zsrc,stream) - the_time();
539 if( (delay-=ahead) > 0. ) {
540 usleep((int)(delay*1000000.0/2.));
542 more_data |= !mpeg3_end_of_audio(zsrc,0);
552 int main(int ac, char **av)
565 //zmpeg3_t* zsrc = mpeg3_open("/tmp/dat",&ret);
566 //zmpeg3_t* zsrc = mpeg3_zopen(0,"/tmp/dat",&ret,ZIO_UNBUFFERED+ZIO_SINGLE_ACCESS+ZIO_SEQUENTIAL);
567 //zmpeg3_t* zsrc = mpeg3_open("/tmp/dat.toc",&ret);
568 //zmpeg3_t* zsrc = mpeg3_open("/root/LimeWire/Shared/Britney Spears - Pepsi Commercial with Bob Dole.mpeg",&ret);
569 //zmpeg3_t* zsrc = mpeg3_open("/tmp/dat.mp3",&ret);
570 //zmpeg3_t* zsrc = mpeg3_open("/dvd/VIDEO_TS/VTS_01_0.IFO",&ret);
571 //zmpeg3_t* zsrc = mpeg3_open("/home/dat2.vts",&ret);
572 //zmpeg3_t* zsrc = mpeg3_open("/dvd/BDMV/STREAM/00000.m2ts",&ret);
573 //zmpeg3_t* zsrc = mpeg3_open("/root/xcolorbars1.mpg",&ret);
574 zmpeg3_t* zsrc = mpeg3_open(av[1],&ret);
576 printf(" ret = %d\n",ret);
577 if( ret != 0 ) exit(1);
582 zmpeg3_t* zsrc1 = zsrc;
584 zmpeg3_t* zsrc1 = mpeg3_open_copy(zsrc->fs->path, zsrc, &ret);
588 mpeg3_set_cpus(zsrc,3);
591 if( stat(zsrc->fs->path, &st_buf) >= 0 ) {
592 if( (pos = (st_buf.st_size & ~0x7ffl) - 0x800000l) < 0 )
596 mpeg3_seek_byte(zsrc, pos);
597 mpeg3_show_subtitle(zsrc, 0, 0);
598 signal(SIGINT,sigint);
601 pthread_create(&the_audio, NULL, audio_thread, (void*)zsrc1);
604 pthread_create(&the_video, NULL, video_thread, (void*)zsrc);
607 pthread_join(the_video,NULL);
610 pthread_join(the_audio,NULL);