diff options
-rw-r--r-- | doc/help-pdp_fcqt.pd | 53 | ||||
-rw-r--r-- | modules/pdp_fcqt.c | 341 |
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 |