aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/help-pdp_fcqt.pd53
-rw-r--r--modules/pdp_fcqt.c341
2 files changed, 394 insertions, 0 deletions
diff --git a/doc/help-pdp_fcqt.pd b/doc/help-pdp_fcqt.pd
new file mode 100644
index 0000000..7eff685
--- /dev/null
+++ b/doc/help-pdp_fcqt.pd
@@ -0,0 +1,53 @@
+#N canvas 237 21 712 664 10;
+#X obj 268 64 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 370 44 open \$1;
+#X obj 369 20 openpanel;
+#X obj 354 3 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X floatatom 316 99 5 0 0 0 - - -;
+#X msg 225 65 stop;
+#X obj 323 68 hsl 300 15 0 1000 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 257 135 metro 70;
+#X obj 558 272 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 558 324 pdp_control;
+#X msg 558 297 thread \$1;
+#X floatatom 558 385 5 0 0 0 - - -;
+#X obj 558 356 route pdp_drop;
+#X floatatom 264 257 5 0 0 0 - - -;
+#X floatatom 295 282 5 0 0 0 - - -;
+#X text 315 257 Number of frames decoded;
+#X text 344 281 Total number of frames;
+#X floatatom 317 164 5 0 0 0 - - -;
+#X text 368 164 Frame command;
+#X obj 316 183 t b f;
+#X text 81 394 written by Yves Degoyon;
+#X obj 218 293 pdp_xv;
+#X text 81 360 pdp_fcqt : fast & compressed quicktime movie reader
+;
+#X text 81 377 ( frames are cached and compressed and no audio decoding
+);
+#X floatatom 326 306 5 0 0 0 - - -;
+#X text 372 305 Frame rate;
+#X obj 225 222 pdp_fcqt;
+#X connect 0 0 7 0;
+#X connect 1 0 26 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 4 0 7 1;
+#X connect 5 0 7 0;
+#X connect 6 0 4 0;
+#X connect 7 0 26 0;
+#X connect 8 0 10 0;
+#X connect 9 0 12 0;
+#X connect 10 0 9 0;
+#X connect 12 0 11 0;
+#X connect 17 0 19 0;
+#X connect 19 0 26 0;
+#X connect 19 1 26 1;
+#X connect 26 0 21 0;
+#X connect 26 1 13 0;
+#X connect 26 2 14 0;
+#X connect 26 3 24 0;
diff --git a/modules/pdp_fcqt.c b/modules/pdp_fcqt.c
new file mode 100644
index 0000000..e7be248
--- /dev/null
+++ b/modules/pdp_fcqt.c
@@ -0,0 +1,341 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Yves Degoyon <ydegoyon@free.fr>
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+#include "pdp.h"
+#include "pdp_llconv.h"
+#include "time.h"
+#include "sys/time.h"
+#include <quicktime/lqt.h>
+#include <quicktime/colormodels.h>
+#include <bzlib.h> // bz2 compression routines
+
+typedef struct pdp_fcqt_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+ t_outlet *x_curframe;
+ t_outlet *x_nbframes;
+ t_outlet *x_framerate;
+
+ int packet0;
+ bool initialized;
+
+ t_int x_vwidth;
+ t_int x_vheight;
+ t_int x_vsize;
+ t_int x_fsize; // frames size
+ t_int x_length;
+ t_int x_current_frame;
+ t_int x_cursec;
+ t_int x_framescount;
+
+ unsigned char * qt_rows[3];
+
+ unsigned char * qt_frame;
+ quicktime_t *qt;
+ int qt_cmodel;
+
+ unsigned int** x_frames;
+ t_int* x_fsizes;
+
+} t_pdp_fcqt;
+
+
+
+static void pdp_fcqt_close(t_pdp_fcqt *x)
+{
+ t_int fi;
+
+ if (x->initialized){
+ quicktime_close(x->qt);
+ if ( x->qt_frame ) freebytes(x->qt_frame, x->x_vsize*3/2);
+ for ( fi=0; fi<x->x_length; fi++ )
+ {
+ if ( x->x_frames[fi] ) freebytes( x->x_frames[fi], x->x_fsizes[fi] );
+ }
+ if ( x->x_frames ) freebytes( x->x_frames, x->x_length*sizeof(unsigned int*) );
+ x->initialized = false;
+ }
+
+}
+
+static void pdp_fcqt_open(t_pdp_fcqt *x, t_symbol *name)
+{
+ t_int fi, osize, ret;
+ unsigned int *odata, *cdata;
+
+ post("pdp_fcqt: opening %s", name->s_name);
+
+ pdp_fcqt_close(x);
+
+ x->qt = quicktime_open(name->s_name, 1, 0); // read=yes, write=no
+
+ if (!(x->qt)){
+ post("pdp_fcqt: error opening qt file");
+ x->initialized = false;
+ return;
+ }
+
+ if (!quicktime_has_video(x->qt)) {
+ post("pdp_fcqt: no video stream");
+ quicktime_close(x->qt);
+ x->initialized = false;
+ return;
+
+ }
+ else if (!quicktime_supported_video(x->qt,0)) {
+ post("pdp_fcqt: unsupported video codec\n");
+ quicktime_close(x->qt);
+ x->initialized = false;
+ return;
+ }
+ else
+ {
+ x->qt_cmodel = BC_YUV420P;
+ x->x_vwidth = quicktime_video_width(x->qt,0);
+ x->x_vheight = quicktime_video_height(x->qt,0);
+ x->x_vsize = x->x_vwidth * x->x_vheight;
+ x->qt_frame = (unsigned char*)getbytes(x->x_vsize+(x->x_vsize>>1));
+ x->qt_rows[0] = &x->qt_frame[0];
+ x->qt_rows[2] = &x->qt_frame[x->x_vsize];
+ x->qt_rows[1] = &x->qt_frame[x->x_vsize + (x->x_vsize>>2)];
+
+ quicktime_set_cmodel(x->qt, x->qt_cmodel);
+ x->initialized = true;
+ x->x_length = quicktime_video_length(x->qt,0);
+ outlet_float(x->x_nbframes, (float)x->x_length);
+
+ }
+
+ // read all frames
+ x->x_current_frame = 0;
+ x->x_frames = (unsigned int**) getbytes( x->x_length*sizeof(unsigned int*) );
+ x->x_fsizes = (t_int*) getbytes( x->x_length*sizeof(t_int) );
+ x->x_fsize = 0;
+ if ( !x->x_frames )
+ {
+ post("pdp_fcqt: couldn't allocate memory for frames(x->x_frames)" );
+ quicktime_close(x->qt);
+ x->initialized = false;
+ return;
+ }
+
+ // allocate data used for compression
+ osize = ( x->x_vsize + (x->x_vsize>>1) ) << 1;
+ odata = (unsigned int*) getbytes( osize );
+ cdata = (unsigned int*) getbytes( osize );
+ if ( !odata || !cdata )
+ {
+ post("pdp_fcqt: couldn't allocate memory for frames (odata/cdata)" );
+ quicktime_close(x->qt);
+ x->initialized = false;
+ return;
+ }
+
+ for ( fi=0; fi<x->x_length; fi++ )
+ {
+ lqt_decode_video(x->qt, x->qt_rows, 0);
+
+ switch(x->qt_cmodel){
+ case BC_YUV420P:
+ pdp_llconv(x->qt_frame, RIF_YVU__P411_U8, odata, RIF_YVU__P411_S16,
+ x->x_vwidth, x->x_vheight);
+
+ x->x_fsizes[fi] = osize;
+ if ( ( ret = BZ2_bzBuffToBuffCompress( (char*)cdata,
+ &x->x_fsizes[fi],
+ (char*)odata,
+ osize,
+ 9, 0, 0 ) ) == BZ_OK )
+ {
+ post( "pdp_fcqt : bz2 compression (%d)->(%d) gain:%d",
+ osize, x->x_fsizes[fi], osize/x->x_fsizes[fi] );
+ x->x_fsize += x->x_fsizes[fi];
+ x->x_frames[fi] = (unsigned int*) getbytes( x->x_fsizes[fi] );
+ if ( !x->x_frames[fi] )
+ {
+ post("pdp_fcqt: couldn't allocate memory for frames" );
+ quicktime_close(x->qt);
+ x->initialized = false;
+ return;
+ }
+ memcpy( x->x_frames[fi], cdata, x->x_fsizes[fi] );
+ }
+ else
+ {
+ post( "pdp_fcqt : bz2 compression failed (ret=%d)", ret );
+ }
+ break;
+
+ default:
+ post("pdp_fcqt : error on decode: unkown colour model");
+ break;
+ }
+
+ }
+
+ if ( odata ) freebytes( odata, osize );
+ if ( cdata ) freebytes( cdata, osize );
+
+ post("pdp_fcqt: allocated memory for %d frames (size=%db %dM)",
+ x->x_length, x->x_fsize, x->x_fsize/(1024*1024) );
+}
+
+
+static void pdp_fcqt_bang(t_pdp_fcqt *x)
+{
+ t_int object, ret, dsize, psize;
+ short int* data;
+ t_pdp* header;
+ struct timeval etime;
+
+ if (!(x->initialized)){
+ //post("pdp_fcqt: no qt file opened");
+ return;
+ }
+
+ object = pdp_packet_new_image_YCrCb( x->x_vwidth, x->x_vheight );
+ header = pdp_packet_header(object);
+ data = (short int *) pdp_packet_data(object);
+
+ header->info.image.encoding = PDP_IMAGE_YV12;
+ header->info.image.width = x->x_vwidth;
+ header->info.image.height = x->x_vheight;
+
+ x->x_current_frame = ( x->x_current_frame + 1 ) % x->x_length;
+ // post( "pdp_fcqt : current frame : %d", x->x_current_frame );
+
+ psize = (x->x_vsize+(x->x_vsize>>1))<<1;
+ dsize = psize;
+ if ( ( ret = BZ2_bzBuffToBuffDecompress( (char*)data,
+ &dsize,
+ (char *) x->x_frames[x->x_current_frame],
+ x->x_fsizes[x->x_current_frame],
+ 0, 0 ) ) == BZ_OK )
+ {
+ // post( "pdp_fcqt : decompressed frame %d : (%d)->(%d)",
+ // x->x_current_frame, x->x_fsizes[x->x_current_frame], dsize );
+ if ( dsize != psize )
+ {
+ post( "pdp_fcqt : warning : decompressed size seems wrong! : (%d)->(%d) (should be %d)",
+ x->x_fsizes[x->x_current_frame], dsize, psize );
+ }
+ }
+ else
+ {
+ post( "pdp_fcqt : bz2 decompression failed (ret=%d)", ret );
+ return;
+ }
+
+ if ( gettimeofday(&etime, NULL) == -1)
+ {
+ post("pdp_fcqt : could not get time" );
+ }
+ if ( etime.tv_sec != x->x_cursec )
+ {
+ x->x_cursec = etime.tv_sec;
+ outlet_float(x->x_framerate, (float)x->x_framescount);
+ x->x_framescount = 0;
+ }
+ x->x_framescount++;
+
+ outlet_float(x->x_curframe, (float)x->x_current_frame);
+ pdp_packet_pass_if_valid(x->x_outlet0, &object);
+
+}
+
+static void pdp_fcqt_frame_cold(t_pdp_fcqt *x, t_floatarg frameindex)
+{
+ int frame = (int)frameindex;
+ int length;
+
+
+ if (!(x->initialized)) return;
+
+ length = quicktime_video_length(x->qt,0);
+
+ frame = (frame >= length) ? length-1 : frame;
+ frame = (frame < 0) ? 0 : frame;
+
+ // post("pdp_fcqt : frame cold : setting video position to : %d", frame );
+ quicktime_set_video_position(x->qt, frame, 0);
+}
+
+static void pdp_fcqt_frame(t_pdp_fcqt *x, t_floatarg frameindex)
+{
+ // pdp_fcqt_frame_cold(x, frameindex);
+ pdp_fcqt_bang(x);
+}
+
+static void pdp_fcqt_free(t_pdp_fcqt *x)
+{
+ pdp_fcqt_close(x);
+}
+
+t_class *pdp_fcqt_class;
+
+void *pdp_fcqt_new(void)
+{
+ t_pdp_fcqt *x = (t_pdp_fcqt *)pd_new(pdp_fcqt_class);
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold"));
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_curframe = outlet_new(&x->x_obj, &s_float);
+ x->x_nbframes = outlet_new(&x->x_obj, &s_float);
+ x->x_framerate = outlet_new(&x->x_obj, &s_float);
+
+ x->packet0 = -1;
+ x->x_cursec = -1;
+ x->x_framescount = 0;
+
+ x->initialized = false;
+
+ return (void *)x;
+}
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_fcqt_setup(void)
+{
+ pdp_fcqt_class = class_new(gensym("pdp_fcqt"), (t_newmethod)pdp_fcqt_new,
+ (t_method)pdp_fcqt_free, sizeof(t_pdp_fcqt), 0, A_NULL);
+
+ class_addmethod(pdp_fcqt_class, (t_method)pdp_fcqt_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_fcqt_class, (t_method)pdp_fcqt_close, gensym("close"), A_NULL);
+ class_addmethod(pdp_fcqt_class, (t_method)pdp_fcqt_open, gensym("open"), A_SYMBOL, A_NULL);
+ class_addfloat (pdp_fcqt_class, (t_method)pdp_fcqt_frame);
+ class_addmethod(pdp_fcqt_class, (t_method)pdp_fcqt_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_fcqt_class, nullfn, gensym("signal"), 0);
+ class_sethelpsymbol( pdp_fcqt_class, gensym("pdp_fcqt.pd") );
+
+}
+
+#ifdef __cplusplus
+}
+#endif