Max 5 API Reference
00001 /* 00002 Copyright 2001-2005 - Cycling '74 00003 Joshua Kit Clayton jkc@cycling74.com 00004 Jeremy Bernstein jeremy@bootsquad.com 00005 */ 00006 00007 #include "jit.qt.movie.h" 00008 #include "jit.charset.h" 00009 00010 // to check on Windows 00011 // MediaContainsDisplayOffsets: available in QT7 SDK? 00012 00013 /** 00014 * @defgroup qtmoviemod jit.qt.movie Module 00015 @ingroup jitter 00016 */ 00017 00018 void *_jit_qt_movie_class; 00019 00020 t_symbol *ps_track, *ps_dialog, *ps_scrap, *ps_noshift, *ps_scale; 00021 t_symbol *ps_inplace, *ps_compress, *ps_faststart, *ps_activeonly; 00022 t_symbol *ps_fxsrc1, *ps_fxsrc2, *ps_fxtrk, *ps_bgtrack; 00023 t_symbol *ps_get_window_ptr,*ps_class_jit_window; 00024 t_symbol *ps_framereport, *ps_loopreport, *ps_done; 00025 t_symbol *ps_loadram, *ps_unloadram, *ps_voclist, *ps_vocmodes, *ps_exporterlist; 00026 t_symbol *ps_colormode, *ps_argb, *ps_uyvy; 00027 t_symbol *ps_readfile, *ps_readscrap, *ps_readurl, *ps_import; 00028 t_symbol *ps_export,*ps_exportimage,*ps_savemovie,*ps_savemovieas,*ps_savemoviecopy,*ps_importfile; 00029 t_symbol *ps__none_, *ps_asyncread, *ps_asyncimport, *ps_async, *ps_asyncstop, *ps_vol; 00030 t_symbol *ps_flatten, *ps_read, *ps_stop, *ps_fps, *ps_start, *ps_asyncreadfile, *ps_asyncreadurl, *ps_unloadram_cached; 00031 t_symbol *ps_free, *ps_dropped; 00032 t_symbol *ps_readfile_unthread, *ps_readurl_unthread, *ps_import_unthread; 00033 t_symbol *ps_rebuild; 00034 00035 #ifdef __APPLE_CC__ 00036 t_symbol *ps_nobox, *ps_box, *ps_atomarray, *ps_typedmess; 00037 #else 00038 static t_symbol *ps_nobox, *ps_box, *ps_atomarray, *ps_typedmess; 00039 #endif 00040 00041 Boolean qt6, qt64, qt65, qt7, inited; 00042 00043 #ifdef MAC_VERSION 00044 CFBundleRef frameBundle = NULL; 00045 00046 EnterMoviesOnThreadPtr mEnterMoviesOnThread; 00047 ExitMoviesOnThreadPtr mExitMoviesOnThread; 00048 AttachMovieToCurrentThreadPtr mAttachMovieToCurrentThread; 00049 DetachMovieFromCurrentThreadPtr mDetachMovieFromCurrentThread; 00050 GetMovieThreadAttachStatePtr mGetMovieThreadAttachState; 00051 00052 typedef OSErr (*AttachTimeBaseToCurrentThreadPtr)(TimeBase); 00053 typedef OSErr (*DetachTimeBaseFromCurrentThreadPtr)(TimeBase); 00054 00055 DetachTimeBaseFromCurrentThreadPtr mDetachTimeBaseFromCurrentThread; 00056 AttachTimeBaseToCurrentThreadPtr mAttachTimeBaseToCurrentThread; 00057 00058 #ifdef NOTYET 00059 typedef OSErr (*SetMovieVisualBrightnessPtr)(Movie, Float32, UInt32); 00060 typedef OSErr (*GetMovieVisualBrightnessPtr)(Movie, Float32 *, UInt32); 00061 SetMovieVisualBrightnessPtr mSetMovieVisualBrightness; 00062 GetMovieVisualBrightnessPtr mGetMovieVisualBrightness; 00063 #endif // NOTYET 00064 #else 00065 HINSTANCE hQtLib = NULL; 00066 #endif 00067 00068 typedef Boolean (*MediaContainsDisplayOffsetsPtr)(Media); 00069 MediaContainsDisplayOffsetsPtr mMediaContainsDisplayOffsets; 00070 typedef TimeValue64 (*GetMediaDisplayDurationPtr)(Media); 00071 GetMediaDisplayDurationPtr mGetMediaDisplayDuration; 00072 00073 00074 #if defined (MAC_VERSION) && (!TARGET_RT_MAC_MACHO) 00075 enum { 00076 kQTEnterMoviesFlagDontSetComponentsThreadMode = 1L << 0 00077 }; 00078 #endif 00079 00080 t_hashtab *mthash, *athash; 00081 00082 #ifdef NOTYET 00083 t_jit_err jit_qt_movie_brightness_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av); 00084 t_jit_err jit_qt_movie_brightness_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av); 00085 #endif 00086 00087 void jit_qt_movie_init_late(void); 00088 00089 //#define TASKTEST 00090 #define JIT_MIN_TASKTIME 30 00091 static void TaskNeededSoonerCallback(TimeValue duration, unsigned long flags, void *refcon); 00092 void jit_qt_movie_task_schedule(t_jit_qt_movie *x); 00093 00094 //#define FLASH_ENABLE 00095 #ifdef FLASH_ENABLE 00096 void jit_qt_movie_flash_enable(void); 00097 Boolean IsFlashEnabled(void); 00098 Boolean EnableFlash(void); 00099 #endif 00100 00101 #pragma mark basic 00102 #pragma mark - 00103 00104 t_jit_err jit_qt_movie_init(void) 00105 { 00106 long attrflags=0; 00107 t_jit_object *attr; 00108 t_jit_object *mop; 00109 00110 _jit_qt_movie_class = jit_class_new("jit_qt_movie",(method)jit_qt_movie_new,(method)jit_qt_movie_free, 00111 sizeof(t_jit_qt_movie),A_DEFLONG,A_DEFLONG,0L); 00112 00113 mop = jit_object_new(_jit_sym_jit_mop,0,1); 00114 jit_mop_single_type(mop, _jit_sym_char); 00115 jit_mop_single_planecount(mop, 4); 00116 jit_class_addadornment(_jit_qt_movie_class,mop); 00117 00118 //add methods 00119 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_matrix_calc, "matrix_calc", A_CANT, 0L); 00120 00121 mthash = hashtab_new(0); 00122 athash = hashtab_new(0); 00123 00124 //add attributes 00125 attrflags = JIT_ATTR_GET_DEFER_LOW | JIT_ATTR_SET_USURP_LOW; 00126 CLASS_STICKY_ATTR(_jit_qt_movie_class, "category", 0, "Temporal"); 00127 attr = jit_object_new(_jit_sym_jit_attr_offset,"time",_jit_sym_long,attrflags, 00128 (method)jit_qt_movie_time_get,(method)jit_qt_movie_proxy_attr,0L); 00129 jit_class_addattr(_jit_qt_movie_class,attr); 00130 jit_qt_movie_addattr(attr, jit_qt_movie_time_set); 00131 attr = jit_object_new(_jit_sym_jit_attr_offset,"loop",_jit_sym_char,attrflags, 00132 (method)0L,(method)jit_qt_movie_loop,calcoffset(t_jit_qt_movie,loop)); 00133 jit_class_addattr(_jit_qt_movie_class,attr); 00134 attr = jit_object_new(_jit_sym_jit_attr_offset,"autostart",_jit_sym_char,attrflags, 00135 (method)0L,(method)0L,calcoffset(t_jit_qt_movie,autostart)); 00136 jit_class_addattr(_jit_qt_movie_class,attr); 00137 attr = jit_object_new(_jit_sym_jit_attr_offset,"preroll",_jit_sym_char,attrflags, 00138 (method)0L,(method)0L,calcoffset(t_jit_qt_movie,preroll)); 00139 jit_class_addattr(_jit_qt_movie_class,attr); 00140 attr = jit_object_new(_jit_sym_jit_attr_offset,"interp",_jit_sym_char,attrflags, 00141 (method)0L,(method)0L,calcoffset(t_jit_qt_movie,interp)); 00142 jit_class_addattr(_jit_qt_movie_class,attr); 00143 attr = jit_object_new(_jit_sym_jit_attr_offset,"rate",_jit_sym_float32,attrflags, 00144 (method)0L,(method)jit_qt_movie_proxy_attr,calcoffset(t_jit_qt_movie,rate)); 00145 jit_class_addattr(_jit_qt_movie_class,attr); 00146 jit_qt_movie_addattr(attr, jit_qt_movie_rate_set); 00147 attr = jit_object_new(_jit_sym_jit_attr_offset,"loopstart",_jit_sym_long,attrflags, 00148 (method)jit_qt_movie_loopstart_get,(method)jit_qt_movie_loopstart,calcoffset(t_jit_qt_movie,looppoints[0])); 00149 jit_class_addattr(_jit_qt_movie_class,attr); 00150 attr = jit_object_new(_jit_sym_jit_attr_offset,"loopend",_jit_sym_long,attrflags, 00151 (method)jit_qt_movie_loopend_get,(method)jit_qt_movie_loopend,calcoffset(t_jit_qt_movie,looppoints[1])); 00152 jit_class_addattr(_jit_qt_movie_class,attr); 00153 attr = jit_object_new(_jit_sym_jit_attr_offset,"loopreport",_jit_sym_char,attrflags, 00154 (method)0L,(method)jit_qt_movie_loopreport,calcoffset(t_jit_qt_movie,loopreport)); 00155 jit_class_addattr(_jit_qt_movie_class,attr); 00156 attr = jit_object_new(_jit_sym_jit_attr_offset_array,"looppoints",_jit_sym_long,2,attrflags, 00157 (method)jit_qt_movie_looppoints_get,(method)jit_qt_movie_looppoints,0/*fix*/,calcoffset(t_jit_qt_movie,looppoints)); 00158 jit_class_addattr(_jit_qt_movie_class,attr); 00159 attr = jit_object_new(_jit_sym_jit_attr_offset,"use_movie_loop",_jit_sym_char,attrflags, 00160 (method)0L,(method)0L,calcoffset(t_jit_qt_movie, use_movie_loop)); 00161 jit_class_addattr(_jit_qt_movie_class,attr); 00162 attr = jit_object_new(_jit_sym_jit_attr_offset,"usemovieloop",_jit_sym_char,attrflags, // synonym 00163 (method)0L,(method)0L,calcoffset(t_jit_qt_movie, use_movie_loop)); 00164 jit_class_addattr(_jit_qt_movie_class,attr); 00165 attr = jit_object_new(_jit_sym_jit_attr_offset,"framereport",_jit_sym_char,attrflags, 00166 (method)0L,(method)0L,calcoffset(t_jit_qt_movie, framereport)); 00167 jit_class_addattr(_jit_qt_movie_class,attr); 00168 CLASS_STICKY_ATTR_CLEAR(_jit_qt_movie_class, "category"); 00169 00170 CLASS_STICKY_ATTR(_jit_qt_movie_class, "category", 0, "Misc"); 00171 attr = jit_object_new(_jit_sym_jit_attr_offset,"vol",_jit_sym_float32,attrflags, 00172 (method)0L,(method)jit_qt_movie_vol_set,calcoffset(t_jit_qt_movie,vol)); 00173 jit_class_addattr(_jit_qt_movie_class,attr); 00174 attr = jit_object_new(_jit_sym_jit_attr_offset,"autosave",_jit_sym_char,attrflags, 00175 (method)0L,(method)0L,calcoffset(t_jit_qt_movie, autosave)); 00176 jit_class_addattr(_jit_qt_movie_class,attr); 00177 attr = jit_object_new(_jit_sym_jit_attr_offset,"poster",_jit_sym_long,attrflags, 00178 (method)jit_qt_movie_poster_get,(method)jit_qt_movie_poster_set,0L); 00179 jit_class_addattr(_jit_qt_movie_class,attr); 00180 attr = jit_object_new(_jit_sym_jit_attr_offset,"movie_name",_jit_sym_symbol,attrflags, 00181 (method)jit_qt_movie_moviename_get,(method)jit_qt_movie_rename, 0L); 00182 jit_class_addattr(_jit_qt_movie_class,attr); 00183 CLASS_ATTR_INVISIBLE(_jit_qt_movie_class, "movie_name", 0); 00184 attr = jit_object_new(_jit_sym_jit_attr_offset,"moviename",_jit_sym_symbol,attrflags, // synonym 00185 (method)jit_qt_movie_moviename_get,(method)jit_qt_movie_rename, 0L); 00186 jit_class_addattr(_jit_qt_movie_class,attr); 00187 attrflags = JIT_ATTR_GET_DEFER_LOW | JIT_ATTR_SET_OPAQUE | JIT_ATTR_SET_OPAQUE_USER; 00188 attr = jit_object_new(_jit_sym_jit_attr_offset,"moviepath",_jit_sym_symbol,attrflags, 00189 (method)jit_qt_movie_moviepath_get,(method)0L, 0L); 00190 jit_class_addattr(_jit_qt_movie_class,attr); 00191 CLASS_STICKY_ATTR_CLEAR(_jit_qt_movie_class, "category"); 00192 00193 CLASS_STICKY_ATTR(_jit_qt_movie_class, "category", 0, "Spatial"); 00194 attrflags = JIT_ATTR_GET_DEFER_LOW | JIT_ATTR_SET_USURP_LOW; 00195 attr = jit_object_new(_jit_sym_jit_attr_offset,"adapt",_jit_sym_char,attrflags, 00196 (method)0L,(method)0L,calcoffset(t_jit_qt_movie,adapt)); 00197 jit_class_addattr(_jit_qt_movie_class,attr); 00198 attr = jit_object_new(_jit_sym_jit_attr_offset_array,"srcrect",_jit_sym_long,4,attrflags, 00199 (method)0L,(method)0L,0/*fix*/,calcoffset(t_jit_qt_movie,srcrect)); 00200 jit_class_addattr(_jit_qt_movie_class,attr); 00201 attr = jit_object_new(_jit_sym_jit_attr_offset_array,"dstrect",_jit_sym_long,4,attrflags, 00202 (method)0L,(method)0L,0/*fix*/,calcoffset(t_jit_qt_movie,dstrect)); 00203 jit_class_addattr(_jit_qt_movie_class,attr); 00204 attr = jit_object_new(_jit_sym_jit_attr_offset,"usesrcrect",_jit_sym_char,attrflags, 00205 (method)0L,(method)0L,calcoffset(t_jit_qt_movie,usesrcrect)); 00206 jit_class_addattr(_jit_qt_movie_class,attr); 00207 attr = jit_object_new(_jit_sym_jit_attr_offset,"usedstrect",_jit_sym_char,attrflags, 00208 (method)0L,(method)0L,calcoffset(t_jit_qt_movie,usedstrect)); 00209 jit_class_addattr(_jit_qt_movie_class,attr); 00210 attr = jit_object_new(_jit_sym_jit_attr_offset,"highquality",_jit_sym_char,attrflags, 00211 (method)jit_qt_movie_getplayhints,(method)jit_qt_movie_playhints,0L); 00212 jit_class_addattr(_jit_qt_movie_class,attr); 00213 attr = jit_object_new(_jit_sym_jit_attr_offset,"singlefield",_jit_sym_char,attrflags, 00214 (method)jit_qt_movie_getplayhints,(method)jit_qt_movie_playhints,0L); 00215 jit_class_addattr(_jit_qt_movie_class,attr); 00216 attr = jit_object_new(_jit_sym_jit_attr_offset,"deinterlace",_jit_sym_char,attrflags, 00217 (method)jit_qt_movie_getplayhints,(method)jit_qt_movie_playhints,0L); 00218 jit_class_addattr(_jit_qt_movie_class,attr); 00219 // uyvy support 00220 attr = jit_object_new(_jit_sym_jit_attr_offset,"colormode",_jit_sym_symbol,attrflags, 00221 (method)0L,(method)jit_qt_movie_colormode,calcoffset(t_jit_qt_movie, colormode)); 00222 jit_class_addattr(_jit_qt_movie_class,attr); 00223 CLASS_STICKY_ATTR_CLEAR(_jit_qt_movie_class, "category"); 00224 00225 // direct to window 00226 attr = jit_object_new(_jit_sym_jit_attr_offset,"window",_jit_sym_symbol,attrflags, 00227 (method)0L,(method)jit_qt_movie_window, calcoffset(t_jit_qt_movie,window)); 00228 jit_class_addattr(_jit_qt_movie_class,attr); 00229 CLASS_ATTR_CATEGORY(_jit_qt_movie_class, "window", 0, "Outputs"); 00230 00231 CLASS_STICKY_ATTR(_jit_qt_movie_class, "category", 0, "Temporal"); 00232 // editmode 00233 attr = jit_object_new(_jit_sym_jit_attr_offset,"editmode",_jit_sym_char,attrflags, 00234 (method)0L,(method)0L,calcoffset(t_jit_qt_movie, editmode)); 00235 jit_class_addattr(_jit_qt_movie_class,attr); 00236 attr = jit_object_new(_jit_sym_jit_attr_offset,"edittime",_jit_sym_long,attrflags, 00237 (method)jit_qt_movie_edittime_get,(method)jit_qt_movie_edittime_set,0L); 00238 jit_class_addattr(_jit_qt_movie_class,attr); 00239 // unique 00240 attr = jit_object_new(_jit_sym_jit_attr_offset,"unique",_jit_sym_char,attrflags, 00241 (method)0L,(method)jit_qt_movie_unique,calcoffset(t_jit_qt_movie,unique)); 00242 jit_class_addattr(_jit_qt_movie_class,attr); 00243 #ifdef DROPREPORT 00244 attr = jit_object_new(_jit_sym_jit_attr_offset,"dropreport",_jit_sym_char,attrflags, 00245 (method)0L,(method)0L,calcoffset(t_jit_qt_movie,dropreport)); 00246 jit_class_addattr(_jit_qt_movie_class,attr); 00247 #endif 00248 #ifdef NOTYET 00249 attr = jit_object_new(_jit_sym_jit_attr_offset,"brightness",_jit_sym_float32,attrflags, 00250 (method)jit_qt_movie_brightness_get, (method)jit_qt_movie_brightness_set,0L); 00251 jit_class_addattr(_jit_qt_movie_class,attr); 00252 #endif 00253 CLASS_STICKY_ATTR_CLEAR(_jit_qt_movie_class, "category"); 00254 00255 CLASS_STICKY_ATTR(_jit_qt_movie_class, "category", 0, "Timecode"); 00256 // timecode track support 00257 attr = jit_object_new(_jit_sym_jit_attr_offset,"timecodevis",_jit_sym_char,attrflags, 00258 (method)0L,(method)jit_qt_movie_timecodevis_set,calcoffset(t_jit_qt_movie,timecodevis)); 00259 jit_class_addattr(_jit_qt_movie_class,attr); 00260 attrflags = JIT_ATTR_GET_DEFER_LOW | JIT_ATTR_SET_OPAQUE | JIT_ATTR_SET_OPAQUE_USER; 00261 attr = jit_object_new(_jit_sym_jit_attr_offset,"timecodeinfo",_jit_sym_symbol,attrflags, 00262 (method)jit_qt_movie_timecodeinfo_get,(method)0L,0L); 00263 jit_class_addattr(_jit_qt_movie_class,attr); 00264 attr = jit_object_new(_jit_sym_jit_attr_offset,"timecode",_jit_sym_symbol,attrflags, 00265 (method)jit_qt_movie_timecode_get,(method)0L,0L); 00266 jit_class_addattr(_jit_qt_movie_class,attr); 00267 CLASS_STICKY_ATTR_CLEAR(_jit_qt_movie_class, "category"); 00268 00269 CLASS_STICKY_ATTR(_jit_qt_movie_class, "category", 0, "Temporal"); 00270 // get only 00271 attr = jit_object_new(_jit_sym_jit_attr_offset,"timescale",_jit_sym_long,attrflags, 00272 (method)jit_qt_movie_timescale_get,(method)0L,0L); 00273 jit_class_addattr(_jit_qt_movie_class,attr); 00274 attr = jit_object_new(_jit_sym_jit_attr_offset,"framecount",_jit_sym_long,attrflags, 00275 (method)jit_qt_movie_framecount_get,(method)0L,0L); 00276 jit_class_addattr(_jit_qt_movie_class,attr); 00277 attr = jit_object_new(_jit_sym_jit_attr_offset,"fps",_jit_sym_float32,attrflags, 00278 (method)jit_qt_movie_fps_get,(method)0L,0L); 00279 jit_class_addattr(_jit_qt_movie_class,attr); 00280 attr = jit_object_new(_jit_sym_jit_attr_offset,"movierate",_jit_sym_float32,attrflags, 00281 (method)jit_qt_movie_getmovierate,(method)0L,0L); 00282 jit_class_addattr(_jit_qt_movie_class,attr); 00283 CLASS_STICKY_ATTR_CLEAR(_jit_qt_movie_class, "category"); 00284 00285 CLASS_STICKY_ATTR(_jit_qt_movie_class, "category", 0, "Spatial"); 00286 attr = jit_object_new(_jit_sym_jit_attr_offset,"movie_dim",_jit_sym_long,attrflags, 00287 (method)jit_qt_movie_moviedim_get,(method)0L); 00288 jit_class_addattr(_jit_qt_movie_class,attr); 00289 attr = jit_object_new(_jit_sym_jit_attr_offset,"moviedim",_jit_sym_long,attrflags, // synonym 00290 (method)jit_qt_movie_moviedim_get,(method)0L); 00291 jit_class_addattr(_jit_qt_movie_class,attr); 00292 CLASS_STICKY_ATTR_CLEAR(_jit_qt_movie_class, "category"); 00293 00294 // set on, if created from max.jit.qtmovie 00295 attrflags = JIT_ATTR_GET_OPAQUE | JIT_ATTR_GET_OPAQUE_USER | JIT_ATTR_SET_OPAQUE | JIT_ATTR_SET_OPAQUE_USER; 00296 attr = jit_object_new(_jit_sym_jit_attr_offset,"optimize",_jit_sym_char,attrflags, 00297 (method)0L,(method)0L,calcoffset(t_jit_qt_movie, optimize)); 00298 jit_class_addattr(_jit_qt_movie_class,attr); 00299 00300 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "dispose", A_USURP_LOW, 0L); 00301 jit_qt_movie_addmethod("dispose", jit_qt_movie_dispose); 00302 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "start", A_DEFER_LOW, 0L); 00303 jit_qt_movie_addmethod("start", jit_qt_movie_start); 00304 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "stop", A_DEFER_LOW, 0L); 00305 jit_qt_movie_addmethod("stop", jit_qt_movie_stop2); 00306 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "jump", A_DEFER_LOW, 0L); 00307 jit_qt_movie_addmethod("jump", jit_qt_movie_jump); 00308 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "jump_true", A_DEFER_LOW, 0L); 00309 jit_qt_movie_addmethod("jump_true", jit_qt_movie_jump_true); 00310 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "frame", A_DEFER_LOW, 0L); 00311 jit_qt_movie_addmethod("frame", jit_qt_movie_frame); 00312 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "frame_true", A_DEFER_LOW, 0L); 00313 jit_qt_movie_addmethod("frame_true", jit_qt_movie_frame_true); 00314 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "loadram", A_USURP_LOW, 0L); 00315 jit_qt_movie_addmethod("loadram", jit_qt_movie_loadram); 00316 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_proxy_method, "unloadram",A_USURP_LOW, 0L); 00317 jit_qt_movie_addmethod("unloadram", jit_qt_movie_unloadram); 00318 // pseudo-methods 00319 jit_qt_movie_addmethod("readfile", jit_qt_movie_readfile); 00320 jit_qt_movie_addmethod("asyncreadfile", jit_qt_movie_readfile); 00321 jit_qt_movie_addmethod("readfile_unthread", jit_qt_movie_readfile_unthread); 00322 jit_qt_movie_addmethod("readurl", jit_qt_movie_readurl); 00323 jit_qt_movie_addmethod("asyncreadurl", jit_qt_movie_readurl); 00324 jit_qt_movie_addmethod("readurl_unthread", jit_qt_movie_readurl_unthread); 00325 jit_qt_movie_addmethod("readscrap", jit_qt_movie_readscrap); 00326 jit_qt_movie_addmethod("asyncstop", jit_qt_movie_stop2); 00327 jit_qt_movie_addmethod("unloadram_cached", jit_qt_movie_unloadram_cached); 00328 jit_qt_movie_addmethod("import", jit_qt_movie_importfile); 00329 jit_qt_movie_addmethod("asyncimport", jit_qt_movie_importfile); 00330 jit_qt_movie_addmethod("import_unthread", jit_qt_movie_importfile_unthread); 00331 jit_qt_movie_addmethod("free", jit_qt_movie_freefn); 00332 00333 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_kill, "kill", A_USURP_LOW, 0L); 00334 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_newmovie, "newmovie", A_USURP_LOW, 0L); 00335 00336 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_notify, "notify", A_CANT, 0L); 00337 jit_class_addmethod(_jit_qt_movie_class, (method)jit_object_register, "register", A_CANT, 0L); //can register 00338 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_mreset, "mreset", A_CANT, 0L); //can register 00339 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_clear, "clear", A_DEFER_LOW, 0L); 00340 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_open, "open", A_CANT, 0L); 00341 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_ismovie, "ismovie", A_CANT, 0L); 00342 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_dim, "dim", A_CANT, 0L); 00343 jit_class_addmethod(_jit_qt_movie_class, (method)jit_qt_movie_matrixattach, "attach", A_CANT, 0L); 00344 00345 jit_qt_movie_init_js(_jit_qt_movie_class); 00346 jit_qt_movie_init_export(_jit_qt_movie_class); 00347 jit_qt_movie_init_tracksupport(_jit_qt_movie_class); 00348 jit_qt_movie_init_editing(_jit_qt_movie_class); 00349 jit_qt_movie_init_scrap(_jit_qt_movie_class); 00350 jit_qt_movie_init_url(_jit_qt_movie_class); 00351 jit_qt_movie_init_flash(_jit_qt_movie_class); 00352 jit_qt_movie_init_voc(_jit_qt_movie_class); 00353 jit_qt_movie_init_fxbg(_jit_qt_movie_class); 00354 jit_qt_movie_init_tracksnd(_jit_qt_movie_class); 00355 jit_qt_movie_init_userdata(_jit_qt_movie_class); 00356 jit_qt_movie_init_vr(_jit_qt_movie_class); 00357 00358 jit_class_register(_jit_qt_movie_class); 00359 00360 quittask_install((method)jit_qt_movie_quittask, NULL); 00361 00362 inited = false; 00363 00364 ps_track = gensym("track"); 00365 ps_dialog = gensym("dialog"); 00366 ps_scrap = gensym("scrap"); 00367 ps_noshift = gensym("noshift"); 00368 ps_scale = gensym("scale"); 00369 ps_inplace = gensym("inplace"); 00370 ps_compress = gensym("compress"); 00371 ps_faststart = gensym("faststart"); 00372 ps_activeonly = gensym("activeonly"); 00373 ps_import = gensym("import"); 00374 00375 ps_fxsrc1 = gensym("___effect_src1"); 00376 ps_fxsrc2 = gensym("___effect_src2"); 00377 ps_fxtrk = gensym("___effect_track"); 00378 ps_bgtrack = gensym("___bgcolor_track"); 00379 00380 ps_framereport = gensym("framereport"); 00381 ps_loopreport = gensym("loopreport"); 00382 ps_done = gensym("done"); 00383 00384 ps_get_window_ptr = gensym("get_window_ptr"); 00385 ps_class_jit_window = gensym("class_jit_window"); 00386 00387 ps_voclist = gensym("voclist"); 00388 ps_vocmodes = gensym("vocmodes"); 00389 ps_exporterlist = gensym("exporterlist"); 00390 ps_loadram = gensym("loadram"); 00391 ps_unloadram = gensym("unloadram"); 00392 ps_flatten = gensym("flatten"); 00393 ps_read = gensym("read"); 00394 ps_colormode = gensym("colormode"); 00395 ps_argb = gensym("argb"); 00396 ps_uyvy = gensym("uyvy"); 00397 00398 ps_readfile = gensym("readfile"); 00399 ps_asyncreadfile = gensym("asyncreadfile"); 00400 ps_readfile_unthread = gensym("readfile_unthread"); 00401 ps_readurl = gensym("readurl"); 00402 ps_asyncreadurl = gensym("asyncreadurl"); 00403 ps_readurl_unthread = gensym("readurl_unthread"); 00404 ps_readscrap = gensym("readscrap"); 00405 ps_export = gensym("export"); 00406 ps_exportimage = gensym("exportimage"); 00407 ps_savemovie = gensym("savemovie"); 00408 ps_savemovieas = gensym("savemovieas"); 00409 ps_savemoviecopy = gensym("savemoviecopy"); 00410 ps_importfile = gensym("importfile"); 00411 ps_box = gensym("box"); 00412 ps_nobox = gensym("nobox"); 00413 ps_atomarray = gensym("atomarray"); 00414 ps_typedmess = gensym("typedmess"); 00415 ps__none_ = gensym("<none>"); 00416 ps_async = gensym("async"); 00417 ps_asyncread = gensym("asyncread"); 00418 ps_asyncimport = gensym("asyncimport"); 00419 ps_import_unthread = gensym("import_unthread"); 00420 ps_asyncstop = gensym("asyncstop"); 00421 ps_unloadram_cached = gensym("unloadram_cached"); 00422 ps_free = gensym("free"); 00423 // support for async reads 00424 ps_stop = gensym("stop"); 00425 ps_fps = gensym("fps"); 00426 ps_start = gensym("start"); 00427 ps_vol = gensym("vol"); 00428 ps_dropped = gensym("dropped"); 00429 ps_rebuild = gensym("rebuild"); 00430 00431 jit_qt_movie_threading_init(); 00432 return JIT_ERR_NONE; 00433 } 00434 00435 void jit_qt_movie_init_late(void) 00436 { 00437 long vers; 00438 00439 Gestalt(gestaltQuickTimeVersion , &vers); 00440 qt6 = (vers >= 0x06000000) ? true : false; 00441 qt64 = (vers >= 0x06408000) ? true : false; 00442 qt65 = (vers >= 0x06500000) ? true : false; 00443 qt7 = (vers >= 0x07000000) ? true : false; 00444 00445 //#if defined (MAC_VERSION) && (!TARGET_RT_MAC_MACHO) 00446 #ifdef MAC_VERSION 00447 if (qt64) 00448 jit_qt_movie_framework_init(); 00449 #else 00450 if (qt64) 00451 jit_qt_movie_qtlib_init(); 00452 // what to do for windows? GetProcAddress()??? 00453 #endif 00454 00455 #if 0 00456 #ifdef MAC_VERSION // these not defined on Windows 00457 mEnterMoviesOnThread = (qt64) ? EnterMoviesOnThread : NULL; 00458 mExitMoviesOnThread = (qt64) ? ExitMoviesOnThread : NULL; 00459 mAttachMovieToCurrentThread = (qt64) ? AttachMovieToCurrentThread : NULL; 00460 mDetachMovieFromCurrentThread = (qt64) ? DetachMovieFromCurrentThread : NULL; 00461 mGetMovieThreadAttachState = (qt64) ? GetMovieThreadAttachState : NULL; 00462 mAttachTimeBaseToCurrentThread = (qt64) ? AttachTimeBaseToCurrentThread : NULL; 00463 mDetachTimeBaseFromCurrentThread = (qt64) ? DetachTimeBaseFromCurrentThread : NULL; 00464 #endif 00465 mMediaContainsDisplayOffsets = (qt7) ? MediaContainsDisplayOffsets : NULL; 00466 mMovieAudioExtractionBegin = (qt7) ? MovieAudioExtractionBegin : NULL; 00467 mMovieAudioExtractionEnd = (qt7) ? MovieAudioExtractionEnd : NULL; 00468 mMovieAudioExtractionFillBuffer = (qt7) ? MovieAudioExtractionFillBuffer : NULL; 00469 mMovieAudioExtractionGetProperty = (qt7) ? MovieAudioExtractionGetProperty : NULL; 00470 mMovieAudioExtractionGetPropertyInfo = (qt7) ? MovieAudioExtractionGetPropertyInfo : NULL; 00471 mMovieAudioExtractionSetProperty = (qt7) ? MovieAudioExtractionSetProperty : NULL; 00472 #endif 00473 #ifdef FLASH_ENABLE 00474 jit_qt_movie_flash_enable(); 00475 #endif 00476 inited = true; 00477 } 00478 00479 void jit_qt_movie_quittask(void) 00480 { 00481 hashtab_chuck(mthash); 00482 hashtab_chuck(athash); 00483 #ifdef MAC_VERSION 00484 if (frameBundle) 00485 CFRelease(frameBundle); 00486 if (sysBundle) 00487 CFRelease(sysBundle); 00488 #else 00489 if (hQtLib) 00490 FreeLibrary(hQtLib); 00491 #endif 00492 } 00493 00494 #ifdef FLASH_ENABLE 00495 enum { 00496 MediaEnablePref = FOUR_CHAR_CODE('scmh'), 00497 MediaEnableType = FOUR_CHAR_CODE('xmpt') 00498 }; 00499 00500 enum { 00501 AppleMediaOwner = FOUR_CHAR_CODE('appl') 00502 }; 00503 00504 typedef struct QTEnableRec { 00505 OSType media; 00506 OSType owner; 00507 } QTMediaEnable; 00508 00509 void jit_qt_movie_flash_enable(void) 00510 { 00511 if (!IsFlashEnabled()) { 00512 if (EnableFlash()) 00513 jit_object_error((t_object *)x,"jit.qt.movie: Flash was disabled for QuickTime; enabled"); 00514 else 00515 jit_object_error((t_object *)x,"jit.qt.movie: error enabling Flash for QuickTime"); 00516 } 00517 } 00518 00519 Boolean IsFlashEnabled(void) 00520 { 00521 Boolean enabled = false; 00522 QTAtomContainer prefs; 00523 QTAtom atom; 00524 SInt32 size; 00525 QTMediaEnable *data; 00526 00527 if (GetQuickTimePreference(MediaEnablePref, &prefs) == noErr && prefs) { 00528 atom = QTFindChildByIndex(prefs, kParentAtomIsContainer, MediaEnablePref, 1, NULL); 00529 if (atom) { 00530 atom = QTFindChildByIndex(prefs, atom, MediaEnableType, 1, NULL); 00531 if (atom) { 00532 QTLockContainer(prefs); 00533 if (QTGetAtomDataPtr(prefs, atom, &size, (Ptr *) &data) == noErr) { 00534 if (size == sizeof(QTMediaEnable) && EndianU32_BtoN(data->media) == FlashMediaType && EndianU32_BtoN(data->owner) == AppleMediaOwner) 00535 enabled = true; 00536 } 00537 QTUnlockContainer(prefs); 00538 } 00539 } 00540 QTDisposeAtomContainer(prefs); 00541 } 00542 return enabled; 00543 } 00544 00545 Boolean EnableFlash(void) 00546 { 00547 QTAtomContainer prefs; 00548 QTAtom atom; 00549 QTMediaEnable data; 00550 Boolean enabled = false; 00551 00552 if (QTNewAtomContainer(&prefs) == noErr && prefs) { 00553 if (QTInsertChild(prefs, kParentAtomIsContainer, MediaEnablePref, 0, 1, 0, NULL, &atom) == noErr) { 00554 data.media = EndianU32_NtoB(FlashMediaType); 00555 data.owner = EndianU32_NtoB(AppleMediaOwner); 00556 if (QTInsertChild(prefs, atom, MediaEnableType, 0, 1, sizeof(QTMediaEnable), &data, &atom) == noErr) 00557 if (SetQuickTimePreference(MediaEnablePref, prefs) == noErr) 00558 enabled = true; 00559 } 00560 QTDisposeAtomContainer(prefs); 00561 } 00562 return enabled && IsFlashEnabled(); 00563 } 00564 #endif // FLASH_ENABLE 00565 00566 #ifdef MAC_VERSION 00567 void jit_qt_movie_framework_init(void) 00568 { 00569 OSStatus err; 00570 00571 err = LoadFrameworkBundle(CFSTR("QuickTime.framework"), &frameBundle); 00572 if (err == noErr) { 00573 mEnterMoviesOnThread = (EnterMoviesOnThreadPtr)CFBundleGetFunctionPointerForName 00574 (frameBundle, CFSTR("EnterMoviesOnThread")); 00575 mExitMoviesOnThread = (ExitMoviesOnThreadPtr)CFBundleGetFunctionPointerForName 00576 (frameBundle, CFSTR("ExitMoviesOnThread")); 00577 mAttachMovieToCurrentThread = (AttachMovieToCurrentThreadPtr)CFBundleGetFunctionPointerForName 00578 (frameBundle, CFSTR("AttachMovieToCurrentThread")); 00579 mDetachMovieFromCurrentThread = (DetachMovieFromCurrentThreadPtr)CFBundleGetFunctionPointerForName 00580 (frameBundle, CFSTR("DetachMovieFromCurrentThread")); 00581 mGetMovieThreadAttachState = (GetMovieThreadAttachStatePtr)CFBundleGetFunctionPointerForName 00582 (frameBundle, CFSTR("GetMovieThreadAttachState")); 00583 mAttachTimeBaseToCurrentThread = (AttachTimeBaseToCurrentThreadPtr)CFBundleGetFunctionPointerForName 00584 (frameBundle, CFSTR("AttachTimeBaseToCurrentThread")); 00585 mDetachTimeBaseFromCurrentThread = (DetachTimeBaseFromCurrentThreadPtr)CFBundleGetFunctionPointerForName 00586 (frameBundle, CFSTR("DetachTimeBaseFromCurrentThread")); 00587 #ifdef NOTYET 00588 if (qt7) { 00589 mGetMovieVisualBrightness = (GetMovieVisualBrightnessPtr)CFBundleGetFunctionPointerForName 00590 (frameBundle, CFSTR("GetMovieVisualBrightness")); 00591 mSetMovieVisualBrightness = (SetMovieVisualBrightnessPtr)CFBundleGetFunctionPointerForName 00592 (frameBundle, CFSTR("SetMovieVisualBrightness")); 00593 } 00594 #endif 00595 if (qt7) { 00596 mMediaContainsDisplayOffsets = (MediaContainsDisplayOffsetsPtr)CFBundleGetFunctionPointerForName 00597 (frameBundle, CFSTR("MediaContainsDisplayOffsets")); 00598 00599 mMovieAudioExtractionBegin = (MovieAudioExtractionBeginPtr)CFBundleGetFunctionPointerForName 00600 (frameBundle, CFSTR("MovieAudioExtractionBegin")); 00601 mMovieAudioExtractionEnd = (MovieAudioExtractionEndPtr)CFBundleGetFunctionPointerForName 00602 (frameBundle, CFSTR("MovieAudioExtractionEnd")); 00603 mMovieAudioExtractionFillBuffer = (MovieAudioExtractionFillBufferPtr)CFBundleGetFunctionPointerForName 00604 (frameBundle, CFSTR("MovieAudioExtractionFillBuffer")); 00605 mMovieAudioExtractionGetProperty = (MovieAudioExtractionGetPropertyPtr)CFBundleGetFunctionPointerForName 00606 (frameBundle, CFSTR("MovieAudioExtractionGetProperty")); 00607 mMovieAudioExtractionGetPropertyInfo = (MovieAudioExtractionGetPropertyInfoPtr)CFBundleGetFunctionPointerForName 00608 (frameBundle, CFSTR("MovieAudioExtractionGetPropertyInfo")); 00609 mMovieAudioExtractionSetProperty = (MovieAudioExtractionSetPropertyPtr)CFBundleGetFunctionPointerForName 00610 (frameBundle, CFSTR("MovieAudioExtractionSetProperty")); 00611 mGetMediaDisplayDuration = (GetMediaDisplayDurationPtr)CFBundleGetFunctionPointerForName 00612 (frameBundle, CFSTR("GetMediaDisplayDuration")); 00613 if ((!mMediaContainsDisplayOffsets) || 00614 (!mMovieAudioExtractionBegin) || 00615 (!mMovieAudioExtractionEnd) || 00616 (!mMovieAudioExtractionFillBuffer) || 00617 (!mMovieAudioExtractionGetProperty) || 00618 (!mMovieAudioExtractionGetPropertyInfo) || 00619 (!mMovieAudioExtractionSetProperty) || 00620 (!mGetMediaDisplayDuration)) 00621 { 00622 post("warning: Jitter thinks QT 7 is installed, but cannot load some QT 7 functions"); 00623 post("spigot~ and other QT 7 specific Jitter features will be disabled."); 00624 post("Please try reinstalling QT"); 00625 qt7=0; 00626 } 00627 } 00628 } 00629 else post("error %d in framework_init", err); 00630 } 00631 #else 00632 void jit_qt_movie_qtlib_init(void) 00633 { 00634 HKEY hKey = NULL; 00635 DWORD valtype; 00636 DWORD rv; 00637 char pathname[1024]; 00638 DWORD pathlen = sizeof(pathname); 00639 00640 hQtLib = NULL; 00641 00642 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Apple Computer, Inc.\\QuickTime", 0, KEY_ALL_ACCESS, &hKey); 00643 if (rv == ERROR_SUCCESS) { 00644 rv = RegQueryValueEx(hKey, "QTExtDir", 0, &valtype, (LPBYTE)pathname, &pathlen); 00645 if (rv == ERROR_SUCCESS) { 00646 // let's hope this isn't bigger than 1023 bytes 00647 strcat(pathname, "QTMLClient.dll"); 00648 hQtLib = LoadLibrary(pathname); 00649 } 00650 } 00651 if (!hQtLib) { 00652 hQtLib = LoadLibrary("QTMLClient.dll"); 00653 } 00654 if (hQtLib) { 00655 if (qt7) { 00656 mMediaContainsDisplayOffsets = (MediaContainsDisplayOffsetsPtr)GetProcAddress(hQtLib, "MediaContainsDisplayOffsets"); 00657 mMovieAudioExtractionBegin = (MovieAudioExtractionBeginPtr)GetProcAddress(hQtLib, "MovieAudioExtractionBegin"); 00658 mMovieAudioExtractionEnd = (MovieAudioExtractionEndPtr)GetProcAddress(hQtLib, "MovieAudioExtractionEnd"); 00659 mMovieAudioExtractionFillBuffer = (MovieAudioExtractionFillBufferPtr)GetProcAddress(hQtLib, "MovieAudioExtractionFillBuffer"); 00660 mMovieAudioExtractionGetProperty = (MovieAudioExtractionGetPropertyPtr)GetProcAddress(hQtLib, "MovieAudioExtractionGetProperty"); 00661 mMovieAudioExtractionGetPropertyInfo = (MovieAudioExtractionGetPropertyInfoPtr)GetProcAddress(hQtLib, "MovieAudioExtractionGetPropertyInfo"); 00662 mMovieAudioExtractionSetProperty = (MovieAudioExtractionSetPropertyPtr)GetProcAddress(hQtLib, "MovieAudioExtractionSetProperty"); 00663 mGetMediaDisplayDuration = (GetMediaDisplayDurationPtr)GetProcAddress(hQtLib, "GetMediaDisplayDuration"); 00664 if ((!mMediaContainsDisplayOffsets) || 00665 (!mMovieAudioExtractionBegin) || 00666 (!mMovieAudioExtractionEnd) || 00667 (!mMovieAudioExtractionFillBuffer) || 00668 (!mMovieAudioExtractionGetProperty) || 00669 (!mMovieAudioExtractionGetPropertyInfo) || 00670 (!mMovieAudioExtractionSetProperty) || 00671 (!mGetMediaDisplayDuration)) 00672 { 00673 //jit_object_post((t_object *)x,"warning: Jitter thinks QT 7 is installed, but cannot load some QT 7 functions"); 00674 //jit_object_post((t_object *)x,"spigot~ and other QT 7 specific Jitter features will be disabled."); 00675 //jit_object_post((t_object *)x,"check /WINDOWS/system32 for an out of date qtmlclient.dll, or try reinstalling QT"); 00676 post("warning: Jitter thinks QT 7 is installed, but cannot load some QT 7 functions"); 00677 post("spigot~ and other QT 7 specific Jitter features will be disabled."); 00678 post("check /WINDOWS/system32 for an out of date qtmlclient.dll, or try reinstalling QT"); 00679 qt7=0; 00680 } 00681 } 00682 } else { 00683 if (qt7) { 00684 //jit_object_post((t_object *)x,"warning: Jitter thinks QT 7 is installed, but cannot load some QT 7 functions"); 00685 //jit_object_post((t_object *)x,"spigot~ and other QT 7 specific Jitter features will be disabled."); 00686 //jit_object_post((t_object *)x,"check /WINDOWS/system32 for an out of date qtmlclient.dll, or try reinstalling QT"); 00687 post("warning: Jitter thinks QT 7 is installed, but cannot load some QT 7 functions"); 00688 post("spigot~ and other QT 7 specific Jitter features will be disabled."); 00689 post("check /WINDOWS/system32 for an out of date qtmlclient.dll, or try reinstalling QT"); 00690 qt7=0; 00691 } 00692 } 00693 } 00694 #endif 00695 00696 void jit_qt_movie_dim(t_jit_qt_movie *x, long width, long height) 00697 { 00698 x->dim[0] = width; 00699 x->dim[1] = height; 00700 } 00701 00702 /** 00703 * Constructs instance of t_jit_qt_movie. 00704 * 00705 * @ingroup qtmoviemod 00706 * 00707 * @param width output matrix width 00708 * @param height output matrix height 00709 * 00710 * @return t_jit_qt_movie object pointer 00711 * 00712 * @warning This function is not exported, but is provided 00713 * for reference when calling via jit_object_new. 00714 */ 00715 t_jit_qt_movie *jit_qt_movie_new(long width, long height) 00716 { 00717 t_jit_qt_movie *x; 00718 t_jit_matrix_info info; 00719 Rect boundsRect; 00720 int err = JIT_ERR_OUT_OF_MEM; //default error 00721 00722 if (width<1) width=1; 00723 if (height<1) height=1; 00724 00725 if (x = (t_jit_qt_movie *)jit_object_alloc(_jit_qt_movie_class)) { 00726 XQT_EnterMovies(); // workaround for init_late in jitlib 00727 #ifdef MAC_VERSION 00728 // if (qt64) 00729 // mEnterMoviesOnThread(kQTEnterMoviesFlagDontSetComponentsThreadMode); 00730 #endif 00731 if (!inited) 00732 jit_qt_movie_init_late(); 00733 x->rate = 1.; 00734 x->movie = NULL; 00735 x->loadingmovie = FALSE; 00736 x->mes = NULL; 00737 x->tempmovie = NULL; 00738 x->tempmovietype = TEMPMOVIE_NONE; 00739 x->tempmoviescrap_moviedata = NULL; 00740 x->tempmoviescrap_dataref = NULL; 00741 x->collective_moviedata = NULL; 00742 x->collective_dataref = NULL; 00743 x->movie_is_temp = 0; 00744 x->use_movie_loop = 0; 00745 x->exporter = 0; 00746 x->exportercount = 0; 00747 x->exportcomponent = NULL; 00748 x->exportsettings = NULL; 00749 x->exportimage_type = 0; 00750 x->exportimage_settings = NULL; 00751 x->vcodec = _jit_sym_nothing; 00752 x->vcodectype = 0L; 00753 x->vcodecq = codecNormalQuality; 00754 x->vcodecquality = _jit_sym_codec_normal; 00755 x->acodec = _jit_sym_nothing; 00756 x->acodectype = 0L; 00757 00758 x->autosave = 0; 00759 x->loop = LOOP_ON; 00760 x->autostart = 1; 00761 x->offscreen = NULL; 00762 //new offscreen with dimensions width/height 00763 boundsRect.top = 0; 00764 boundsRect.left = 0; 00765 boundsRect.bottom = height; 00766 boundsRect.right = width; 00767 x->movie_rect = boundsRect; 00768 jit_qt_movie_dim(x, width, height); 00769 if (QTNewGWorld(&x->offscreen, k32ARGBPixelFormat, &boundsRect, NULL, NULL, 0)) { 00770 err = JIT_ERR_OUT_OF_MEM; 00771 x->offscreen = NULL; 00772 } else 00773 jit_qt_movie_clear_offscreen(x); // sets clearflag to 0 00774 00775 x->interp = 0; 00776 x->usesrcrect = 0; 00777 x->usedstrect = 0; 00778 x->srcrect[0] = x->dstrect[0] = boundsRect.left; 00779 x->srcrect[1] = x->dstrect[1] = boundsRect.top; 00780 x->srcrect[2] = x->dstrect[2] = boundsRect.right; 00781 x->srcrect[3] = x->dstrect[3] = boundsRect.bottom; 00782 x->looppoints[0] = 0; 00783 x->looppoints[1] = 0; 00784 x->restoreloop = false; 00785 //for qtvr(oddly needs a controller) 00786 x->moviecontroller = NULL; 00787 x->dw = NULL; 00788 x->prepped = 0; 00789 x->voc = 0; 00790 x->mode = 0; 00791 x->vocmode = 0; 00792 x->voc_sound_mode = 0; // normal 00793 x->open = 0; 00794 x->ci = NULL; 00795 x->qtc = NULL; 00796 x->fx = 0; 00797 x->fps = 0.; 00798 00799 x->window = _jit_sym_nothing; 00800 x->temp_window = _jit_sym_nothing; 00801 x->mxname = _jit_sym_nothing; 00802 00803 x->mwrapped = MWRAP_UNWRAPPED; 00804 x->cmode_changed = CMODE_CHANGED; 00805 x->resid = 0; 00806 00807 x->vol = 1.; 00808 00809 x->cb = 0; 00810 x->loopreport = 0; 00811 x->framereport = 0; 00812 x->editmode = EDITMODE_QT; 00813 x->mxmodify = false; 00814 x->optimize = false; // we will not do matrix wrapping unless we've been explicitly told to 00815 x->timecodevis = false; 00816 x->clearflag = false; 00817 x->adapt = false; 00818 x->preroll = false; 00819 x->unique = false; 00820 x->unique_nexttime = 0x80000000; 00821 x->unique_prevtime = 0x7FFFFFFF; 00822 x->unique_lasttime = 0x80000000; 00823 00824 x->unloadram_clock = clock_new(x, (method)jit_qt_movie_unloadram_clockfn); 00825 00826 // uyvy support 00827 x->colormode = ps_argb; 00828 x->pixelformat = k32ARGBPixelFormat; 00829 jit_matrix_info_default(&info); 00830 x->ayuvmatrix = jit_object_new(_jit_sym_jit_matrix, &info); 00831 x->ayuvSmatrix = jit_object_new(_jit_sym_jit_matrix, &info); 00832 info.flags = JIT_MATRIX_DATA_REFERENCE | JIT_MATRIX_DATA_FLAGS_USE; 00833 x->wrapmatrix = jit_object_new(_jit_sym_jit_matrix, &info); 00834 x->uyvy2ayuv = jit_object_new(gensym("jit_uyvy2ayuv")); 00835 x->ayuv2uyvy = jit_object_new(gensym("jit_ayuv2uyvy")); 00836 00837 // Flash 00838 x->progress = NULL; 00839 x->button = false; 00840 x->flash_but = NULL; 00841 x->flash_var = NULL; 00842 x->flash_cb = NULL; 00843 x->flash_chars = NULL; 00844 x->flash_upp = NewQTCallBackUPP(jit_qt_movie_flash_cb); 00845 00846 // spigot~ 00847 x->soc = _jit_sym_nothing; 00848 x->soc_disable = _jit_sym_nothing; 00849 x->soc_extracted = false; 00850 x->sfplay = NULL; 00851 x->sfplayname = _jit_sym_nothing; 00852 x->sfplay_rate = 0; 00853 x->sfplay_clock_enabled = false; 00854 x->sfplay_file = _jit_sym_nothing; 00855 x->aei = NULL; 00856 x->aei_qelem = qelem_new(x, (method)jit_qt_movie_soc_audio_extract); 00857 // end spigot~ 00858 00859 x->start_qelem = qelem_new(x, (method)jit_qt_movie_start); 00860 x->progdl_qelem = qelem_new(x, (method)jit_qt_movie_progdl); 00861 x->prepre = NewMoviePrePrerollCompleteUPP((MoviePrePrerollCompleteProcPtr)jit_qt_movie_preprecomplete); 00862 00863 x->looper = NewQTCallBackUPP(jit_qt_movie_looper); 00864 00865 x->dsp_qelem = qelem_new(x, (method)jit_qt_movie_do_dspstate_notify); 00866 x->dsp_state = 0; 00867 00868 x->requestlinklist = jit_linklist_new(); 00869 x->threadstate = THREADSTATE_NONE; 00870 systhread_mutex_new(&x->threadingmutex, 0); 00871 x->asyncrequestqueue = qelem_new(x, (method)jit_qt_movie_asynchrequestqueue); 00872 x->abort = false; 00873 x->workerstate = true; 00874 systhread_mutex_new(&x->workermutex, 0); 00875 systhread_mutex_new(&x->workerlock, 0); 00876 systhread_cond_new(&x->workercond, 0); 00877 systhread_mutex_new(&x->disposemutex, 0); 00878 systhread_cond_new(&x->disposecond, 0); 00879 systhread_create((method)jit_qt_movie_worker, x, 0, 0, 0, &x->workerthread); 00880 00881 #ifdef TASKTEST 00882 x->taskclock = clock_new(x, (method)jit_qt_movie_task_schedule); 00883 QTInstallNextTaskNeededSoonerCallback(NewQTNextTaskNeededSoonerCallbackUPP(TaskNeededSoonerCallback), 00884 1000, // Millisecond timescale 00885 0, // No flags 00886 (void*)x); 00887 #else 00888 x->taskclock = NULL; 00889 #endif 00890 x->highquality = 1; 00891 x->singlefield = -1; 00892 x->deinterlace = -1; 00893 } else { 00894 x = NULL; 00895 } 00896 00897 return x; 00898 } 00899 00900 void jit_qt_movie_spin(ulong *state, long time) 00901 { 00902 unsigned long start, tc; 00903 long *foo = 0; 00904 00905 //*foo = 10; 00906 #if TARGET_API_MAC_CARBON 00907 tc = start = TickCount(); 00908 while (*state) { 00909 tc = TickCount(); 00910 if (tc - start > time) { 00911 break; 00912 } 00913 } 00914 // jit_object_post((t_object *)x,"spin consumed %ld ticks",tc - start); 00915 #endif 00916 #ifdef WIN_VERSION 00917 // time is specified in mac tick counts, or 1/60 seconds. 00918 // Convert to windows ticks (ms): 00919 time = time * 1000/60; 00920 start = GetTickCount(); /*milliseconds*/ 00921 while (*state) { 00922 SleepEx(10, FALSE); 00923 tc = GetTickCount(); 00924 if((tc - start) > (unsigned long) time) { 00925 break; 00926 } 00927 } 00928 #endif // #ifdef WIN_VERSION 00929 } 00930 00931 void jit_qt_movie_thread_reattach(Movie m) 00932 { 00933 #ifdef MAC_VERSION // reattach after any outstanding threads, if necessary 00934 if (m && qt64) { 00935 Boolean here = false, anywhere = false; 00936 00937 mGetMovieThreadAttachState(m, &here, &anywhere); 00938 if (!here) { 00939 DEBUGPOST(("attaching in thread_reattach")); 00940 mAttachMovieToCurrentThread(m); 00941 } 00942 } 00943 #endif 00944 } 00945 00946 void jit_qt_movie_freefn(t_jit_qt_movie *x) 00947 { 00948 x->workerinfo.m = NULL; 00949 x->workerinfo.data = NULL; 00950 systhread_cond_signal(x->workercond); 00951 } 00952 00953 void jit_qt_movie_free(t_jit_qt_movie *x) 00954 { 00955 jit_qt_movie_proxy_free(x); 00956 systhread_join(x->workerthread, NULL); 00957 jit_qt_movie_thread_reattach(x->movie); 00958 00959 #ifndef WIN_VERSION 00960 if (x->open) 00961 jit_qt_movie_voc_close(x); 00962 #endif // WIN_VERSION 00963 00964 if (x->mes) 00965 DisposeMovieEditState(x->mes); 00966 00967 if (x->exportsettings) 00968 QTDisposeAtomContainer(x->exportsettings); 00969 00970 if (x->exportimage_settings) 00971 QTDisposeAtomContainer(x->exportimage_settings); 00972 00973 if (x->movie) { 00974 StopMovie(x->movie); 00975 jit_qt_movie_soc_rate_set(x, 0); 00976 jit_qt_movie_autosave(x); 00977 jit_qt_movie_dispose(x); // dispose gworld NOT inside anymore 00978 jit_qt_movie_dispose_gworld(x); 00979 } 00980 else { 00981 jit_qt_movie_disposecallback(x,NULL,0,NULL); 00982 jit_qt_movie_dispose_gworld(x); 00983 } 00984 jit_qt_movie_tempmovie_close(x); // to be sure 00985 00986 DisposeQTCallBackUPP(x->flash_upp); 00987 if (x->mxname != _jit_sym_nothing) 00988 jit_object_detach(x->mxname, x); 00989 00990 #ifndef WIN_VERSION 00991 if (x->window!=_jit_sym_nothing) 00992 jit_object_detach(x->window,x); 00993 else if (x->temp_window!=_jit_sym_nothing) 00994 jit_object_detach(x->temp_window,x); 00995 #endif 00996 00997 jit_object_free(x->ayuvmatrix); 00998 jit_object_free(x->ayuvSmatrix); 00999 jit_object_free(x->wrapmatrix); 01000 jit_object_free(x->uyvy2ayuv); 01001 jit_object_free(x->ayuv2uyvy); 01002 01003 if (x->unloadram_clock) 01004 freeobject((t_object *)x->unloadram_clock); 01005 #ifdef TASKTEST 01006 if (x->taskclock) 01007 freeobject((t_object *)x->taskclock); 01008 QTUninstallNextTaskNeededSoonerCallback(NewQTNextTaskNeededSoonerCallbackUPP(TaskNeededSoonerCallback), (void*)x); 01009 #endif 01010 01011 if (x->sfplay || (x->soc != _jit_sym_nothing || x->soc_disable != _jit_sym_nothing)) { 01012 // detach from object 01013 jit_qt_movie_soc_sfplay_detach(x); 01014 // unregister 01015 jit_qt_movie_soc_unregister(x); 01016 } 01017 01018 // DisposeMCActionFilterWithRefConUPP(x->mcactionfilter); 01019 DisposeMoviePrePrerollCompleteUPP(x->prepre); 01020 DisposeQTCallBackUPP(x->looper); 01021 01022 if (x->start_qelem) 01023 qelem_free(x->start_qelem); 01024 if (x->progdl_qelem) 01025 qelem_free(x->progdl_qelem); 01026 if (x->aei_qelem) 01027 qelem_free(x->aei_qelem); 01028 if (x->dsp_qelem) 01029 qelem_free(x->dsp_qelem); 01030 01031 jit_object_free(x->requestlinklist); 01032 systhread_mutex_free(x->threadingmutex); 01033 qelem_free(x->asyncrequestqueue); 01034 systhread_mutex_free(x->workermutex); 01035 systhread_mutex_free(x->workerlock); 01036 systhread_cond_free(x->workercond); 01037 systhread_mutex_free(x->disposemutex); 01038 systhread_cond_free(x->disposecond); 01039 01040 XQT_ExitMovies(); // workaround for init_late in jitlib 01041 } 01042 01043 void jit_qt_movie_notify(t_jit_qt_movie *x, t_symbol *s, t_symbol *msg, void *sender, void *data) 01044 { 01045 if (s == x->window || s == x->temp_window) { 01046 if (msg == _jit_sym_free) { 01047 jit_object_detach(s,x); 01048 x->window = _jit_sym_nothing; 01049 jit_qt_movie_movie_prep(x); 01050 } else if (msg == _jit_sym_block) { 01051 x->temp_window = x->window; 01052 x->window = _jit_sym_nothing; 01053 jit_qt_movie_movie_prep(x); 01054 } 01055 else if (msg == _jit_sym_unblock && x->window == _jit_sym_nothing && x->temp_window != _jit_sym_nothing) { 01056 x->window = x->temp_window; 01057 x->temp_window = _jit_sym_nothing; 01058 jit_qt_movie_movie_prep(x); 01059 } 01060 else if (msg == _jit_sym_modified || msg == ps_rebuild) { 01061 if (x->window != _jit_sym_nothing) 01062 jit_qt_movie_movie_prep(x); 01063 } 01064 return; 01065 } 01066 else if (s == x->mxname && !x->mxmodify) // ignore when it's us 01067 { 01068 if (msg == _jit_sym_setinfo) { 01069 t_jit_matrix_info info; 01070 01071 jit_object_method(sender, _jit_sym_getinfo, &info); 01072 jit_qt_movie_dim(x, info.dim[0], info.dim[1]); 01073 jit_qt_movie_mreset(x); // we have to reset the matrix at once to prevent crashing if the movie tasks 01074 x->mwrapped = MWRAP_TRYAGAIN; // but we also have to make sure that the matrix unwraps 01075 } 01076 else if (msg == _jit_sym_free) { 01077 if (x->mxname != _jit_sym_nothing) 01078 jit_object_detach(x->mxname, x); 01079 jit_qt_movie_mreset(x); 01080 x->mwrapped = MWRAP_TRYAGAIN; // but we also have to make sure that the matrix unwraps 01081 } 01082 } 01083 else if (s == x->sfplayname) { 01084 if (msg == ps_typedmess) { 01085 long ac = 0; 01086 t_atom *av = NULL; 01087 long cue; 01088 01089 object_getvalueof(data, &ac, &av); 01090 if (ac && av && ac > 1) { 01091 cue = atom_getlong(av + 1); 01092 switch (cue) { 01093 case 2: 01094 switch (x->sfplay_cueready) { 01095 case 3: jit_qt_movie_soc_sfplay_setrate(x); break; 01096 case 0: x->sfplay_cueready = cue; break; 01097 default: jit_object_error((t_object *)x, "jit.qt.movie: error parsing spigot~ cue data"); break; 01098 } 01099 break; 01100 case 3: 01101 switch (x->sfplay_cueready) { 01102 case 2: jit_qt_movie_soc_sfplay_setrate(x); break; 01103 case 0: x->sfplay_cueready = cue; break; 01104 default: jit_object_error((t_object *)x, "jit.qt.movie: error parsing spigot~ cue data"); break; 01105 } 01106 break; 01107 default: jit_object_error((t_object *)x, "jit.qt.movie: error parsing spigot~ cue data"); break; 01108 } 01109 } 01110 freebytes(av, sizeof(t_atom) * ac); 01111 } else if (msg == ps_loopreport && x->loopreport) { 01112 jit_qt_movie_looper_notify(x); 01113 } else if (msg == ps_done) { 01114 jit_qt_movie_soc_sfplay_clock_disable(x, true); 01115 } else if (msg == _jit_sym_free) { 01116 jit_qt_movie_soc_sfplay_detach(x); 01117 } 01118 } 01119 #ifndef WIN_VERSION 01120 else { // assumed that it's from the component -- I need to fix this up at some point 01121 if (msg == _jit_sym_free) { 01122 if (x->prepped) { 01123 x->prepped = 0; 01124 } 01125 if (x->dw) { 01126 x->dw = NULL; 01127 } 01128 x->ci = NULL; 01129 x->qtc = NULL; 01130 x->open = 0; 01131 // jit_object_post((t_object *)x,"component closed"); 01132 } 01133 if (msg == gensym("qtcomponent_accessed")) { 01134 long is_owner; 01135 01136 is_owner = (long)jit_object_method(x->qtc, gensym("is_owner"), x); 01137 if (!is_owner) { 01138 x->mode = 0; 01139 jit_qt_movie_voc_close(x); 01140 } 01141 } 01142 } 01143 #endif //WIN_VERSION 01144 } 01145 01146 #pragma mark - 01147 #pragma mark openclose 01148 #pragma mark - 01149 01150 t_jit_err jit_qt_movie_locatefile(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01151 { 01152 t_jit_err err = JIT_ERR_GENERIC; 01153 01154 if (rinfo) { 01155 if (locatefile_extended(rinfo->filename, &rinfo->vol, &rinfo->type, 0L, 0)) 01156 jit_object_error((t_object *)x, "jit.qt.movie: can't find file %s", rinfo->filename); 01157 else err = JIT_ERR_NONE; 01158 rinfo->err = err; 01159 x->moviename = gensym(rinfo->filename); 01160 switch(rinfo->operation) { 01161 case OP_READFILE: 01162 case OP_ASYNCREADFILE: 01163 return jit_qt_movie_readfile_makespec(rinfo->x, rinfo); break; 01164 case OP_IMPORT: 01165 case OP_ASYNCIMPORT: 01166 return jit_qt_movie_importfile_makespec(rinfo->x, rinfo); break; 01167 default: jit_object_error((t_object *)x, "jit.qt.movie: bad operation in jit_qt_movie_locatefile"); break; 01168 } 01169 } 01170 return (err); 01171 } 01172 01173 t_jit_err jit_qt_movie_readfile(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 01174 { 01175 short vol; 01176 long type; 01177 char filename[1024]; 01178 t_symbol *name = _jit_sym_nothing; 01179 t_jit_qt_movie_readinfo *rinfo; 01180 t_atom a; 01181 01182 if (ac && av) 01183 name = jit_atom_getsym(av); 01184 01185 if (name == _jit_sym_nothing) { 01186 name = ps__none_; 01187 if (open_dialog(filename, &vol, &type, 0L, 0)) { 01188 return JIT_ERR_GENERIC; 01189 } 01190 rinfo = (t_jit_qt_movie_readinfo *)sysmem_newptrclear(sizeof(t_jit_qt_movie_readinfo)); 01191 rinfo->x = x; 01192 strcpy(rinfo->filename, filename); 01193 x->moviename = gensym(filename); 01194 rinfo->vol = vol; 01195 rinfo->type = type; 01196 rinfo->async = (s == ps_asyncreadfile) ? true : false; 01197 01198 if (rinfo->async) { 01199 rinfo->operation = OP_ASYNCREADFILE; // this isn't superfluous - we need it in case of mode switches 01200 x->workerinfo.m = (method)jit_qt_movie_readfile_makespec; 01201 x->workerinfo.data = rinfo; 01202 systhread_cond_signal(x->workercond); 01203 } 01204 else {// synchronous 01205 rinfo->operation = OP_READFILE; 01206 return jit_qt_movie_readfile_makespec(x, rinfo); 01207 } 01208 } 01209 else { 01210 rinfo = (t_jit_qt_movie_readinfo *)sysmem_newptrclear(sizeof(t_jit_qt_movie_readinfo)); 01211 rinfo->x = x; 01212 strcpy(rinfo->inputstr, name->s_name); 01213 strcpy(rinfo->filename, name->s_name); 01214 rinfo->async = (s == ps_asyncreadfile) ? true : false; 01215 01216 if (rinfo->async) { 01217 rinfo->operation = OP_ASYNCREADFILE; 01218 x->workerinfo.m = (method)jit_qt_movie_locatefile; 01219 x->workerinfo.data = rinfo; 01220 systhread_cond_signal(x->workercond); 01221 } 01222 else { 01223 rinfo->operation = OP_READFILE; 01224 return jit_qt_movie_locatefile(x, rinfo); // calls jit_qt_movie_readfile_makespec 01225 } 01226 } 01227 return JIT_ERR_NONE; 01228 } 01229 01230 t_jit_err jit_qt_movie_readfile_makespec(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01231 { 01232 t_symbol *name = _jit_sym_nothing; 01233 01234 if (rinfo && !rinfo->err) { 01235 OSErr err; 01236 t_atom a; 01237 01238 #if (defined(MAC_VERSION) && defined(TARGET_RT_MAC_MACHO)) || defined(WIN_VERSION) 01239 if (rinfo->vol > 0) { // from a collective 01240 t_filehandle fh = NULL; 01241 Handle h = NULL; 01242 long size; 01243 short err; 01244 01245 err = path_opensysfile(rinfo->filename, rinfo->vol, &fh, READ_PERM); 01246 if (err) { 01247 jit_object_error((t_object *)x,"jit.qt.movie: can't open %s from collective", rinfo->filename); 01248 goto out; 01249 } 01250 err = sysfile_geteof(fh, &size); 01251 if (err) { 01252 jit_object_error((t_object *)x,"jit.qt.movie: can't get size of %s from collective", rinfo->filename); 01253 goto out; 01254 } 01255 h = NewHandle(size); 01256 if (h) { 01257 HLock(h); 01258 err = sysfile_read(fh, &size, *h); 01259 HUnlock(h); 01260 if (err) { 01261 jit_object_error((t_object *)x,"jit.qt.movie: can't read %s from collective", rinfo->filename); 01262 goto out; 01263 } 01264 } else { 01265 jit_object_error((t_object *)x,"jit.qt.movie: error creating handle for %s in collective", rinfo->filename); 01266 goto out; 01267 } 01268 rinfo->h = h; // don't forget to free this 01269 sysfile_close(fh); 01270 } 01271 #else 01272 if (rinfo->vol > 0) { // old-style collective 01273 unsigned long foundtype; 01274 Handle h = NULL; 01275 01276 if (h = get1namedresource_extended(rinfo->filename, &foundtype, NULL, 0)) { 01277 handle2tempfile(&fs, foundtype, h); 01278 DisposeHandle(h); 01279 } 01280 else { 01281 jit_object_error((t_object *)x, "jit.qt.movie: can't open resource %s", rinfo->filename); 01282 goto out; 01283 } 01284 goto out; 01285 } 01286 #endif 01287 else { 01288 XQT_NewDataReferenceFromMaxPath(rinfo->vol, rinfo->filename, &rinfo->dataRef, &rinfo->dataRefType, &err); 01289 if (err) { 01290 jit_object_error((t_object *)x, "jit.qt.movie: error converting file path to file spec %d", err); 01291 goto out; 01292 } 01293 } 01294 rinfo->err = noErr; 01295 01296 jit_qt_movie_readfile_newmovie(x, rinfo); 01297 if (rinfo->err) { 01298 if (rinfo->async) { // we need to abort the thread and try again - there was a component issue 01299 rinfo->async = false; 01300 rinfo->err = noErr; 01301 01302 DEBUGPOST(("async err, unthreading")); 01303 jit_atom_setobj(&a, rinfo); 01304 jit_qt_movie_proxy_method_front(x, ps_readfile_unthread, 1, &a); 01305 return JIT_ERR_NONE; 01306 } 01307 else goto out; 01308 } 01309 else 01310 return jit_qt_movie_readfile_complete(x, rinfo); 01311 } 01312 01313 out: 01314 DEBUGPOST(("sync err")); 01315 if (rinfo) 01316 jit_qt_movie_readimport_notify(x, rinfo); 01317 return JIT_ERR_GENERIC; 01318 } 01319 01320 /* 01321 else { 01322 if (err == -2048) { 01323 if (rinfo->vol > 0) { 01324 err = FSpDelete(&fs); // why do we do this? 01325 } 01326 } 01327 jit_object_error((t_object *)x, "jit.qt.movie: can't open file %s (openmoviefile %d)",name->s_name,err); 01328 } 01329 } 01330 */ 01331 01332 void jit_qt_movie_readfile_unthread(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 01333 { 01334 DEBUGPOST(("readfile_unthread: %d %X", ac ,av)); 01335 if (ac && av) { 01336 t_jit_qt_movie_readinfo *rinfo = jit_atom_getobj(av); 01337 01338 if (rinfo) { 01339 jit_qt_movie_readfile_newmovie(x, rinfo); 01340 if (rinfo->err) { 01341 jit_object_error((t_object *)x, "jit.qt.movie: error %d creating new movie from file", rinfo->err); 01342 if (rinfo) 01343 jit_qt_movie_readimport_notify(x, rinfo); 01344 } 01345 else 01346 jit_qt_movie_readfile_complete(x, rinfo); 01347 } 01348 } 01349 } 01350 01351 void jit_qt_movie_readfile_newmovie(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01352 { 01353 OSErr err; 01354 t_atom a; 01355 Movie m = NULL; 01356 t_systhread_cond cond; 01357 01358 if (!rinfo->h) { 01359 rinfo->err = NewMovieFromDataRef(&rinfo->m, newMovieActive, &rinfo->resid, rinfo->dataRef, rinfo->dataRefType); 01360 if (!rinfo->err) // this is likely not necessary 01361 SetMovieDefaultDataRef(rinfo->m, rinfo->dataRef, rinfo->dataRefType); 01362 DisposeHandle(rinfo->dataRef); 01363 rinfo->dataRef = NULL; 01364 } else { // opening from handle 01365 Handle dataref; 01366 01367 // Create a data reference handle for our data 01368 PtrToHand(&rinfo->h, &dataref, sizeof(Handle)); 01369 01370 // Cache the data for _dispose 01371 x->collective_moviedata = rinfo->h; 01372 x->collective_dataref = dataref; 01373 rinfo->err = NewMovieFromDataRef(&rinfo->m, newMovieActive, &rinfo->resid, dataref, HandleDataHandlerSubType); 01374 } 01375 if (rinfo->async) { 01376 // try de- and re-attaching movie to see if it works 01377 #ifdef MAC_VERSION 01378 if (rinfo->m) { 01379 if (!rinfo->err) { 01380 rinfo->err = mDetachMovieFromCurrentThread(rinfo->m); 01381 } 01382 if (!rinfo->err) { 01383 rinfo->err = mAttachMovieToCurrentThread(rinfo->m); 01384 } 01385 } 01386 #endif 01387 DEBUGPOST(("rinfo->err: %d, rinfo->m: %X", rinfo->err, rinfo->m)); 01388 if (rinfo->err && rinfo->m) { 01389 DisposeMovie(rinfo->m); // try again, reading unthreaded 01390 rinfo->m = NULL; 01391 // jit_object_error((t_object *)x, "jit.qt.movie: error %d creating movie from file in thread", rinfo->err); 01392 } 01393 } 01394 } 01395 01396 t_jit_err jit_qt_movie_readfile_complete(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01397 { 01398 Movie m; 01399 Handle h = NULL; 01400 char success = false; 01401 OSErr err; 01402 t_jit_qt_movie_readinfo rinfo2 = *rinfo; // rinfo will be freed 01403 01404 DEBUGPOST(("readfile_complete: %X %X", rinfo, rinfo ? rinfo->m : 0)); 01405 if (rinfo && (m = rinfo->m)) { 01406 if (!jit_qt_movie_open(x, m, rinfo)) { 01407 x->resid = rinfo2.resid; 01408 #if 0 01409 GetMovieDefaultDataRef(x->movie, &h, NULL); 01410 if (!h) { 01411 AliasHandle alias; 01412 01413 err = QTNewAlias(&rinfo2.fs, &alias, true); 01414 SetMovieDefaultDataRef(x->movie, (Handle)alias, rAliasType); 01415 if (alias) 01416 DisposeHandle((Handle)alias); 01417 } 01418 else 01419 DisposeHandle(h); 01420 #endif 01421 01422 if (rinfo2.vol > 0) { 01423 x->movie_is_temp = 1; 01424 } 01425 success = true; //success 01426 x->soc_extracted = false; 01427 01428 if (qt7 && x->soc != _jit_sym_nothing) { 01429 jit_qt_movie_export_audio(x, NULL, 0, NULL); 01430 } 01431 } 01432 else { 01433 jit_qt_movie_readimport_notify(x, rinfo); 01434 } 01435 } 01436 return (success) ? JIT_ERR_NONE : JIT_ERR_GENERIC; 01437 } 01438 01439 #ifndef WIN_VERSION //win_todo 01440 Handle get1namedresource_extended(char *name, unsigned long *foundtype, unsigned long *types, long ntypes) 01441 { 01442 long i=0; 01443 Handle h=NULL; 01444 Str255 pname; 01445 unsigned long type; 01446 01447 ctopcpy(pname,name); 01448 01449 if (types) { 01450 while((i<ntypes)) { 01451 if (h=Get1NamedResource(types[i],pname)){ 01452 *foundtype = types[i]; 01453 return h; 01454 } 01455 i++; 01456 } 01457 } else { //find any resource 01458 ntypes=Count1Types(); 01459 while((i++<ntypes)) { 01460 Get1IndType(&type,i); 01461 if (h=Get1NamedResource(type,pname)){ 01462 *foundtype = type; 01463 return h; 01464 } 01465 } 01466 } 01467 01468 return NULL; 01469 } 01470 #endif // WIN_VERSION 01471 01472 t_jit_err jit_qt_movie_readscrap(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 01473 { 01474 Movie m; 01475 char success = false; 01476 long flags; 01477 t_object *arr; 01478 t_atom *arr_av; 01479 long arr_ac = 2; 01480 01481 // flags = newMovieActive;// | ((jit_attr_getlong(x, ps_inbox)) ? newMovieAsyncOK : 0L); 01482 01483 jit_qt_movie_tempscrap_open(x); 01484 m = jit_qt_movie_duplicate_movie(x->tempmovie); 01485 if (m) { 01486 SetMovieActive(m, true); 01487 if (!jit_qt_movie_open(x, m, NULL)) 01488 success = true; 01489 } else { 01490 jit_object_error((t_object *)x, "jit.qt.movie: can't open movie from scrap"); 01491 } 01492 01493 /* m = NewMovieFromScrap(flags); 01494 if (m) { 01495 if (!jit_qt_movie_open(x, m, NULL)) 01496 success = true; 01497 } 01498 else { 01499 jit_qt_movie_tempscrap_open(x); 01500 m = jit_qt_movie_duplicate_movie(x->tempmovie); 01501 jit_qt_movie_tempmovie_close(x); 01502 jit_object_error((t_object *)x, "jit.qt.movie: can't open movie from scrap"); 01503 } 01504 */ 01505 jit_qt_movie_tempmovie_close(x); 01506 return (success) ? JIT_ERR_NONE : JIT_ERR_GENERIC; 01507 } 01508 01509 t_jit_err jit_qt_movie_readurl(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 01510 { 01511 t_symbol *name=_jit_sym_nothing; 01512 long size = 0; 01513 char success = false; 01514 t_jit_qt_movie_readinfo *rinfo; 01515 t_atom a; 01516 01517 rinfo = (t_jit_qt_movie_readinfo *)sysmem_newptrclear(sizeof(t_jit_qt_movie_readinfo)); 01518 rinfo->x = x; 01519 01520 jit_atom_arg_getsym(&name, 0, ac, av); 01521 if (name != _jit_sym_nothing) { 01522 strcpy(rinfo->filename, name->s_name); 01523 rinfo->async = (s == ps_asyncreadurl) ? true : false; 01524 01525 if (rinfo->async) { 01526 rinfo->operation = OP_ASYNCREADURL; 01527 x->workerinfo.m = (method)jit_qt_movie_readurl_newmovie; 01528 x->workerinfo.data = rinfo; 01529 systhread_cond_signal(x->workercond); 01530 } 01531 else { 01532 rinfo->operation = OP_READURL; 01533 return jit_qt_movie_readurl_newmovie(x, rinfo); 01534 } 01535 return JIT_ERR_NONE; 01536 } 01537 return JIT_ERR_GENERIC; 01538 } 01539 01540 t_jit_err jit_qt_movie_readurl_newmovie(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01541 { 01542 t_atom a; 01543 Handle h; 01544 long size; 01545 01546 size = strlen(rinfo->filename) + 1; 01547 h = NewHandle(size); 01548 if (h) { 01549 sysmem_copyptr(rinfo->filename, *h, size); 01550 01551 rinfo->err = NewMovieFromDataRef(&rinfo->m, newMovieActive, NULL, h, URLDataHandlerSubType); 01552 DisposeHandle(h); 01553 if (rinfo->err) { 01554 if (rinfo->async) { // we need to abort the thread and try again - there was a component issue 01555 t_atom a; 01556 01557 rinfo->async = false; 01558 rinfo->err = noErr; 01559 01560 jit_atom_setobj(&a, rinfo); 01561 jit_qt_movie_proxy_method_front(x, ps_readurl_unthread, 1, &a); 01562 return JIT_ERR_NONE; 01563 } 01564 else return JIT_ERR_GENERIC; 01565 } else 01566 return jit_qt_movie_readurl_complete(x, rinfo); 01567 } 01568 return JIT_ERR_GENERIC; 01569 } 01570 01571 void jit_qt_movie_readurl_unthread(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 01572 { 01573 if (ac && av) { 01574 t_jit_qt_movie_readinfo *rinfo = jit_atom_getobj(av); 01575 01576 if (rinfo) { 01577 jit_qt_movie_readurl_newmovie(x, rinfo); 01578 if (rinfo->err) { 01579 jit_object_error((t_object *)x, "jit.qt.movie: error %d reading URL", rinfo->err); 01580 jit_qt_movie_readimport_notify(x, rinfo); 01581 } 01582 } 01583 } 01584 } 01585 01586 t_jit_err jit_qt_movie_readurl_complete(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01587 { 01588 t_symbol *name = _jit_sym_nothing; 01589 char success = false; 01590 Movie m; 01591 01592 if (rinfo && (m = rinfo->m)) { 01593 if (!jit_qt_movie_open(x, m, rinfo)) { 01594 // add movie controller to get resize hint from streaming movie, if present 01595 jit_qt_movie_mc(x); 01596 SetMoviePlayHints(m, hintsAllowDynamicResize, hintsAllowDynamicResize); 01597 success = true; 01598 } 01599 else { 01600 jit_object_error((t_object *)x, "jit.qt.movie: can't open movie from url"); 01601 jit_qt_movie_readimport_notify(x, rinfo); 01602 } 01603 } 01604 return (success) ? JIT_ERR_NONE : JIT_ERR_GENERIC; 01605 } 01606 01607 t_jit_err jit_qt_movie_importfile(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 01608 { 01609 short vol; 01610 long type; 01611 char filename[1024]; 01612 t_symbol *name = _jit_sym_nothing; 01613 t_jit_qt_movie_readinfo *rinfo; 01614 t_atom a; 01615 01616 if (ac && av) 01617 name = jit_atom_getsym(av); 01618 01619 if (name == _jit_sym_nothing || name == ps_dialog) { 01620 name = ps__none_; 01621 if (open_dialog(filename, &vol, &type, 0L, 0)) { 01622 return JIT_ERR_GENERIC; 01623 } 01624 rinfo = (t_jit_qt_movie_readinfo *)sysmem_newptrclear(sizeof(t_jit_qt_movie_readinfo)); 01625 rinfo->x = x; 01626 strcpy(rinfo->filename, filename); 01627 x->moviename = gensym(filename); 01628 rinfo->ac = ac; 01629 rinfo->av = (t_atom *)sysmem_newptr(sizeof(t_atom) * ac); 01630 sysmem_copyptr(av, rinfo->av, sizeof(t_atom) * ac); // copy args over 01631 rinfo->vol = vol; 01632 rinfo->type = type; 01633 rinfo->async = (s == ps_asyncimport) ? true : false; 01634 01635 if (rinfo->async) { 01636 rinfo->operation = OP_ASYNCIMPORT; // this isn't superfluous - we need it in case of mode switches 01637 x->workerinfo.m = (method)jit_qt_movie_importfile_makespec; 01638 x->workerinfo.data = rinfo; 01639 systhread_cond_signal(x->workercond); 01640 } 01641 else {// synchronous 01642 rinfo->operation = OP_IMPORT; 01643 return jit_qt_movie_importfile_makespec(x, rinfo); 01644 } 01645 } 01646 else { 01647 rinfo = (t_jit_qt_movie_readinfo *)sysmem_newptrclear(sizeof(t_jit_qt_movie_readinfo)); 01648 rinfo->x = x; 01649 strcpy(rinfo->inputstr, name->s_name); 01650 strcpy(rinfo->filename, name->s_name); 01651 rinfo->ac = ac; 01652 rinfo->av = (t_atom *)sysmem_newptr(sizeof(t_atom) * ac); 01653 sysmem_copyptr(av, rinfo->av, sizeof(t_atom) * ac); // copy args over 01654 rinfo->async = (s == ps_asyncimport) ? true : false; 01655 01656 if (rinfo->async) { 01657 rinfo->operation = OP_ASYNCIMPORT; 01658 x->workerinfo.m = (method)jit_qt_movie_locatefile; 01659 x->workerinfo.data = rinfo; 01660 systhread_cond_signal(x->workercond); 01661 } 01662 else { 01663 rinfo->operation = OP_IMPORT; 01664 return jit_qt_movie_locatefile(x, rinfo); // calls jit_qt_movie_importfile_makespec 01665 } 01666 } 01667 return JIT_ERR_NONE; 01668 } 01669 01670 t_jit_err jit_qt_movie_importfile_makespec(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01671 { 01672 t_symbol *name = _jit_sym_nothing; 01673 long err; 01674 t_atom a; 01675 01676 if (rinfo && !rinfo->err) { 01677 XQT_NewDataReferenceFromMaxPath(rinfo->vol, rinfo->filename, &rinfo->dataRef, &rinfo->dataRefType, &err); 01678 if (err) { 01679 jit_object_error((t_object *)x, "jit.qt.movie: can't open file %s (XQT_NewDataReferenceFromMaxPath %d)", rinfo->filename, err); 01680 goto out; 01681 } 01682 01683 rinfo->err = noErr; 01684 01685 jit_qt_movie_importfile_newmovie(x, rinfo); 01686 if (rinfo->err) { 01687 if (rinfo->async) { 01688 rinfo->async = false; 01689 rinfo->err = noErr; 01690 01691 jit_atom_setobj(&a, rinfo); 01692 jit_qt_movie_proxy_method_front(x, ps_import_unthread, 1, &a); 01693 return JIT_ERR_NONE; 01694 } 01695 else goto out; 01696 } 01697 else 01698 return JIT_ERR_NONE; 01699 } 01700 out: 01701 if (rinfo) 01702 jit_qt_movie_readimport_notify(x, rinfo); 01703 return JIT_ERR_GENERIC; 01704 } 01705 01706 void jit_qt_movie_importfile_unthread(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 01707 { 01708 if (ac && av) { 01709 t_jit_qt_movie_readinfo *rinfo = jit_atom_getobj(av); 01710 01711 if (rinfo) { 01712 jit_qt_movie_importfile_newmovie(x, rinfo); 01713 if (rinfo->err) { 01714 jit_object_error((t_object *)x, "jit.qt.movie: error %d importing new movie from file", rinfo->err); 01715 jit_qt_movie_readimport_notify(x, rinfo); 01716 } 01717 } 01718 } 01719 } 01720 01721 void jit_qt_movie_importfile_newmovie(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 01722 { 01723 t_symbol *tofile = _jit_sym_nothing; 01724 short topath = 0; 01725 Handle toDataRef = NULL; 01726 OSType toDataRefType = 0; 01727 OSErr err; 01728 t_atom *av; 01729 long ac; 01730 long settings = 0; 01731 long flag = 0; 01732 char tempfile = 1; 01733 long offset = 0; 01734 t_symbol *stmp = _jit_sym_nothing; 01735 short resid; 01736 t_jit_qt_movie_readinfo rinfo2; 01737 Movie m = NULL; 01738 char success = false; 01739 char movie_is_temp = false; 01740 01741 av = rinfo->av; 01742 ac = rinfo->ac; 01743 // we do this again 01744 jit_atom_arg_getsym(&stmp, 0, ac, av); 01745 if (stmp != _jit_sym_nothing) 01746 offset++; 01747 01748 jit_atom_arg_getlong(&settings, offset++, ac, av); 01749 if (settings) 01750 flag |= (showUserSettingsDialog | movieFileSpecValid); 01751 01752 jit_atom_arg_getsym(&tofile, offset, ac, av); 01753 if (tofile != _jit_sym_nothing) { 01754 tempfile = 0; 01755 if (tofile == ps_dialog) 01756 tofile = _jit_sym_nothing; 01757 } 01758 01759 if (rinfo->async && (settings || (!tempfile && tofile == _jit_sym_nothing))) { 01760 rinfo->err = -1; // abort async 01761 return; 01762 } 01763 01764 if (tempfile && tofile == _jit_sym_nothing) { //create temp data ref 01765 movie_is_temp = true; 01766 err = !jit_qt_utils_tempfile(NULL, &toDataRef, &toDataRefType); 01767 } 01768 else { 01769 if (rinfo->async) { 01770 rinfo->err = -1; // abort async 01771 return; 01772 } 01773 else 01774 err = jit_qt_utils_moviedataref_create(&tofile, &topath, &toDataRef, &toDataRefType); 01775 } 01776 01777 if (!toDataRef) { 01778 rinfo->err = MAX_ERR_GENERIC; 01779 goto out; 01780 } 01781 01782 rinfo2 = *rinfo; // rinfo will be freed 01783 01784 x->progress = NewMovieProgressUPP((MovieProgressProcPtr)jit_qt_movie_progress); 01785 rinfo->err = ConvertDataRefToMovieDataRef(rinfo->dataRef, rinfo->dataRefType, toDataRef, toDataRefType, FOUR_CHAR_CODE('TVOD'), flag, NULL, (MovieProgressUPP)x->progress, (long)x); 01786 DisposeMovieProgressUPP(x->progress); 01787 x->progress = NULL; 01788 if (rinfo->err) { 01789 // jit_object_error((t_object *)x, "jit.qt.movie: error importing movie (ConvertFileToMovieFile %d)", rinfo->err); 01790 goto out; 01791 } 01792 01793 resid = 0; 01794 if (!(rinfo->err = NewMovieFromDataRef(&rinfo->m, newMovieActive, &resid, toDataRef, toDataRefType))) { 01795 if (!jit_qt_movie_open(x, rinfo->m, rinfo)) { 01796 x->movie_is_temp = movie_is_temp; 01797 SetMovieDefaultDataRef(x->movie, toDataRef, toDataRefType); 01798 success = true; 01799 } 01800 } 01801 out: 01802 if (toDataRef) { 01803 if (!success) { 01804 DeleteMovieStorage(toDataRef, toDataRefType); 01805 x->movie_is_temp = 0; 01806 } 01807 DisposeHandle(toDataRef); 01808 } 01809 return;// (success) ? JIT_ERR_NONE : JIT_ERR_GENERIC; 01810 } 01811 01812 void jit_qt_movie_dispose(t_jit_qt_movie *x) 01813 { 01814 Handle dataRef = NULL; 01815 OSType dataRefType = 0; 01816 Boolean here = true, anywhere; 01817 OSErr err = noErr; 01818 01819 if (x->movie) { 01820 jit_qt_movie_abort(x); // to kill loadram or anything else responding to a progress proc, if necessary 01821 clock_unset(x->unloadram_clock); 01822 #ifdef TASKTEST 01823 clock_unset(x->taskclock); 01824 #endif 01825 AbortPrePrerollMovie(x->movie, err); 01826 // StopMovie(x->movie); // leaving this out now to avoid hiccups 01827 01828 jit_qt_movie_disposecallback(x,NULL,0,NULL); 01829 01830 if (x->movie_is_temp) { 01831 GetMovieDefaultDataRef(x->movie, &dataRef, &dataRefType); 01832 x->movie_is_temp = 0; 01833 } 01834 01835 jit_qt_movie_flash_disposecallback(x); 01836 jit_qt_movie_flash_ll_clear(x); 01837 jit_qt_movie_flash_charlist_delete(x); 01838 01839 if (x->moviecontroller) { 01840 DisposeMovieController(x->moviecontroller); 01841 x->moviecontroller = NULL; 01842 } 01843 01844 if (x->aei) { 01845 qelem_unset(x->aei_qelem); 01846 jit_qt_movie_soc_audio_extract_stop(x, true); 01847 } 01848 jit_qt_movie_soc_sfplay_clock_disable(x, false); 01849 if (x->sfplay) { // kill the sfplay~ for this movie 01850 if (x->sfplay_file != _jit_sym_nothing) { 01851 object_method(x->sfplay, ps_fclose, _jit_sym_nothing); 01852 x->sfplay_file = _jit_sym_nothing; 01853 } 01854 } 01855 01856 DisposeMovie(x->movie); 01857 x->movie = NULL; 01858 01859 // removed, causes problems when asyncreading; gworld should be explicitly disposed as necessary 01860 // jit_qt_movie_dispose_gworld(x); 01861 01862 if (x->collective_dataref) { 01863 DisposeHandle(x->collective_dataref); 01864 x->collective_dataref = NULL; 01865 } 01866 if (x->collective_moviedata) { 01867 DisposeHandle(x->collective_moviedata); 01868 x->collective_moviedata = NULL; 01869 } 01870 if (dataRef) { 01871 if (dataRefType == rAliasType) { 01872 DeleteMovieStorage(dataRef, dataRefType); 01873 } 01874 DisposeHandle(dataRef); 01875 } 01876 x->fx = 0; 01877 x->resid = 0; 01878 x->progdl = 0; 01879 x->cmode_changed = CMODE_CHANGED; 01880 x->fps = 0.; 01881 if (!x->loadingmovie) 01882 x->clearflag = true; 01883 } 01884 systhread_cond_signal(x->disposecond); 01885 } 01886 01887 void jit_qt_movie_kill(t_jit_qt_movie *x) 01888 { 01889 x->movie_is_temp = 1; 01890 jit_qt_movie_dispose(x); // dispose_gworld NOT inside 01891 jit_qt_movie_dispose_gworld(x); 01892 } 01893 01894 Boolean jit_qt_movie_hasdisplayoffsets(Movie m) 01895 { 01896 long count = GetMovieTrackCount(m); 01897 long i; 01898 Track track; 01899 01900 if (!qt7) 01901 return false; 01902 01903 for (i = 1; i <= count; i++) { 01904 track = GetMovieIndTrack(m, i); 01905 if (mMediaContainsDisplayOffsets(GetTrackMedia(track))) 01906 return true; 01907 } 01908 01909 return false; 01910 } 01911 01912 GWorldPtr jit_qt_movie_clone_offscreen(GWorldPtr offscreen); 01913 GWorldPtr jit_qt_movie_clone_offscreen(GWorldPtr offscreen) 01914 { 01915 GWorldPtr newgw = NULL; 01916 Rect r; 01917 PixMapHandle pmh; 01918 OSErr err; 01919 01920 if (offscreen) { 01921 pmh = GetGWorldPixMap(offscreen); 01922 if (pmh) { 01923 GetPixBounds(pmh, &r); 01924 err = QTNewGWorld(&newgw, (**pmh).pixelFormat, &r, NULL, NULL, 0); 01925 if (err == noErr && newgw) { 01926 ImageDescriptionHandle idh; 01927 GWorldPtr oldgw; 01928 GDHandle oldgdh; 01929 01930 GetGWorld(&oldgw, &oldgdh); 01931 SetGWorld(newgw, NULL); 01932 MakeImageDescriptionForPixMap(pmh, &idh); 01933 DecompressImage(GetPixBaseAddr(pmh), idh, GetGWorldPixMap(newgw), nil, &r, srcCopy, nil); 01934 SetGWorld(oldgw, oldgdh); 01935 DisposeHandle((Handle)idh); 01936 return newgw; 01937 } 01938 } 01939 } 01940 return NULL; 01941 } 01942 01943 long jit_qt_movie_open(t_jit_qt_movie *x, Movie m, t_jit_qt_movie_readinfo *rinfo) 01944 { 01945 Track track; 01946 Media media; 01947 CGrafPtr oldport; 01948 GDHandle oldgdh; 01949 Rect r; 01950 OSErr err; 01951 char async = (rinfo && rinfo->async); 01952 GWorldPtr gw = NULL; 01953 01954 DEBUGPOST(("jit.qt.movie open: %X", m)); 01955 if (!m) 01956 return 1; 01957 01958 x->loadingmovie = TRUE; 01959 if (x->movie) { 01960 jit_qt_movie_autosave(x); 01961 if (async) { // this is a little ugly, but nicer than de-attaching the first movie from the thread and then disposing in the worker thread 01962 systhread_mutex_lock(x->disposemutex); 01963 defer_low(x, (method)jit_qt_movie_dispose, NULL, 0, NULL); 01964 systhread_cond_wait(x->disposecond, x->disposemutex); 01965 systhread_mutex_unlock(x->disposemutex); 01966 } else 01967 jit_qt_movie_dispose(x); 01968 } 01969 x->movie = m; 01970 01971 x->cached = false; 01972 01973 GetMovieBox(m, &r); 01974 if (r.left == 0 && r.right == 0 && r.top == 0 && r.bottom == 0) { // no box 01975 r.right = 320; 01976 r.bottom = 240; 01977 } else { 01978 r.right -= r.left; 01979 r.bottom -= r.top; 01980 r.left = 0; 01981 r.top = 0; 01982 } 01983 x->movie_rect = r; 01984 01985 if (err = QTNewGWorld(&gw, x->pixelformat, &x->movie_rect, NULL, NULL, 0)) { 01986 jit_object_error((t_object *)x,"jit.qt.movie: could not create temporary GWorld for open()"); 01987 return 1; 01988 } 01989 jit_qt_movie_do_clear_offscreen(gw, x->colormode); 01990 SetMovieGWorld(m, gw, NULL); 01991 01992 jit_qt_movie_task(x); // must be run once before scanning the objects in the movie 01993 01994 GetGWorld(&oldport, &oldgdh); 01995 SetGWorld(gw, NULL); 01996 01997 jit_qt_movie_movie_prep(x); 01998 01999 // for progressive downloads 02000 QTMovieNeedsTimeTable(m, &x->progdl); 02001 if (x->progdl) { 02002 qelem_set(x->progdl_qelem); 02003 } 02004 x->fx = jit_qt_movie_hasfxtrack(m); 02005 02006 if (x->use_movie_loop) 02007 jit_qt_movie_loopstatus(x); 02008 02009 x->looppoints[0] = 0; 02010 x->looppoints[1] = GetMovieDuration(m); 02011 jit_qt_movie_set_timebase_loop(x); 02012 02013 jit_qt_movie_playhints_do(x); 02014 jit_qt_movie_timecodevis(x); 02015 02016 // check if movie uses frame-reordered codec 02017 x->bframe = jit_qt_movie_hasdisplayoffsets(m); 02018 02019 if (jit_qt_movie_ismpeg(m)) // for some reason this doesn't work during movie_prep 02020 jit_qt_movie_mc(x); 02021 02022 SetGWorld(oldport, oldgdh); 02023 02024 if (track = jit_qt_movie_isflash(m)) { 02025 Boolean autoplay = true, fullscreen = false, looping = false; 02026 02027 // jit_object_post((t_object *)x,"movie has flash track"); 02028 jit_qt_movie_mc(x); 02029 02030 jit_qt_movie_flash_getchars(media = GetTrackMedia(track), &autoplay, &fullscreen, &looping); 02031 // this causes crashing too for some reason 02032 // if (x->flash_cb = NewCallBack(GetMovieTimeBase(m), callBackAtTimeJump)) { 02033 // CallMeWhen(x->flash_cb, x->flash_upp, (long)x, 0, 0, 0); 02034 // } 02035 jit_qt_movie_flash_parsemedia(x, media); 02036 if (async) 02037 jit_qt_movie_proxy_method(x, ps_asyncstop, 0, NULL);//ps_asyncread); // does a loadram 02038 if (autoplay && x->autostart) 02039 jit_qt_movie_proxy_method(x, ps_start, 0, NULL); 02040 } 02041 else { 02042 if (async) 02043 jit_qt_movie_proxy_method(x, ps_asyncstop, 0, NULL);//ps_asyncread); // does a loadram 02044 if (x->autostart) 02045 jit_qt_movie_proxy_method(x, ps_start, 0, NULL); 02046 } 02047 02048 jit_qt_movie_read_final(x, rinfo); 02049 return 0; 02050 } 02051 02052 void jit_qt_movie_readimport_notify(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 02053 { 02054 t_atom a[2]; 02055 t_symbol *s, *name; 02056 02057 name = (*rinfo->inputstr) ? gensym(rinfo->inputstr) : gensym(rinfo->filename); 02058 if (name == _jit_sym_nothing) 02059 name = ps__none_; 02060 jit_atom_setsym(a, name); 02061 jit_atom_setlong(a + 1, rinfo->err ? 0 : 1); 02062 02063 switch(rinfo->operation) { 02064 case OP_IMPORT: 02065 case OP_ASYNCIMPORT: 02066 s = ps_import; break; 02067 default: 02068 s = ps_read; break; 02069 } 02070 if (rinfo->operation < OP_READFILE) // started async 02071 defer_low(x, (method)jit_qt_movie_notify_atomarray_prep, s, 2, a); 02072 02073 if (rinfo->av) 02074 sysmem_freeptr(rinfo->av); 02075 sysmem_freeptr(rinfo); 02076 } 02077 02078 void jit_qt_movie_read_final_cleanup(t_jit_qt_movie *x, Movie m, t_jit_qt_movie_readinfo *rinfo) 02079 { 02080 if (x->window == _jit_sym_nothing && x->temp_window == _jit_sym_nothing) { 02081 GWorldPtr gw; 02082 GDHandle gdh; 02083 02084 GetMovieGWorld(m, &gw, &gdh); 02085 SetMovieGWorld(m, NULL, NULL); 02086 if (gw && gw != x->offscreen) 02087 DisposeGWorld(gw); 02088 } 02089 if (rinfo) 02090 jit_qt_movie_readimport_notify(x, rinfo); // rinfo freed here 02091 } 02092 02093 void jit_qt_movie_read_final(t_jit_qt_movie *x, t_jit_qt_movie_readinfo *rinfo) 02094 { 02095 Movie m = x->movie; 02096 char reattached; 02097 02098 #ifdef MAC_VERSION 02099 if (rinfo) { 02100 reattached = (!rinfo->err && rinfo->async); //ended async 02101 if (reattached) { // ended async 02102 DEBUGPOST(("detaching in read_final")); 02103 mDetachMovieFromCurrentThread(m); 02104 defer_low(x, (method)jit_qt_movie_open_reattach, NULL, 0, NULL); 02105 jit_qt_movie_read_final_cleanup(x, m, rinfo); 02106 return; 02107 } 02108 } 02109 #endif 02110 jit_qt_movie_read_final_cleanup(x, m, rinfo); 02111 jit_qt_movie_open_reattach(x); // call this to set movie volume, as well as reattach 02112 } 02113 02114 void jit_qt_movie_open_reattach(t_jit_qt_movie *x) 02115 { 02116 #ifdef MAC_VERSION 02117 Boolean here, anywhere; 02118 02119 mGetMovieThreadAttachState(x->movie, &here, &anywhere); 02120 if (!here) { 02121 DEBUGPOST(("attaching in open_reattach")); 02122 mAttachMovieToCurrentThread(x->movie); 02123 } 02124 #endif 02125 x->unique_nexttime = 0x80000000; 02126 x->unique_prevtime = 0x7FFFFFFF; 02127 x->unique_lasttime = 0x80000000; 02128 x->loadingmovie = FALSE; 02129 jit_qt_movie_mreset(x); 02130 #ifndef TASKTEST 02131 jit_qt_movie_task(x); 02132 #endif 02133 if (x->soc == _jit_sym_nothing && x->soc_disable == _jit_sym_nothing) 02134 SetMovieVolume(x->movie, x->vol * 255.); 02135 else 02136 SetMovieVolume(x->movie, 0); 02137 x->fps = jit_qt_movie_moviefps_get(x->movie); 02138 x->mwrapped = MWRAP_TRYAGAIN; 02139 } 02140 02141 void jit_qt_movie_movie_prep(t_jit_qt_movie *x) 02142 { 02143 long trackcount, i, err; 02144 OSType type; 02145 Track track; 02146 Media media; 02147 ComponentInstance soc=NULL; 02148 PREP_M 02149 02150 if (!m) 02151 return; 02152 02153 #ifndef WIN_VERSION //win_todo 02154 02155 if (x->mode && x->ci) { 02156 UnsignedFixed sr = eAudioRateDefault; 02157 ComponentInstance clock; 02158 Component sci; 02159 02160 soc = jit_qt_movie_lookup_soc(x); 02161 trackcount = GetMovieTrackCount(m); 02162 x->numaudiotracks = 0; 02163 for (i = 1; i < trackcount + 1; i++) { 02164 track = GetMovieIndTrack(m, i); 02165 media = GetTrackMedia(track); 02166 GetMediaHandlerDescription(media, &type, NULL, NULL); 02167 02168 if (type == SoundMediaType) { 02169 SoundDescriptionHandle sdh; 02170 02171 x->amh[x->numaudiotracks] = GetMediaHandler(media); 02172 x->numaudiotracks++; 02173 02174 if (sdh = (SoundDescriptionHandle)NewHandle(0)) { 02175 GetMediaSampleDescription(media, 1, (SampleDescriptionHandle)sdh); 02176 if (sr < (**sdh).sampleRate) 02177 sr = (**sdh).sampleRate; 02178 DisposeHandle((Handle)sdh); 02179 } 02180 } 02181 } 02182 02183 if (!x->voc_sound_mode) { 02184 // Get the first sound output component associated with the video output component. 02185 // jit_object_post((t_object *)x,"to voc"); 02186 err = QTVideoOutputGetIndSoundOutput(x->ci, 1, &sci); 02187 if (err == noErr) { 02188 SoundInfoList sil; 02189 UnsignedFixed *rates; 02190 UnsignedFixed tmprate = 0; 02191 02192 err = GetSoundOutputInfo(sci, siSampleRateAvailable, &sil); 02193 if (err) { 02194 if (systhread_mutex_trylock(x->workerlock)) { 02195 defer_low(x, (method)jit_qt_movie_movie_prep, NULL, 0, NULL); 02196 return; 02197 } else { 02198 systhread_mutex_unlock(x->workerlock); 02199 jit_object_error((t_object *)x, "jit.qt.movie: error %d GetSoundOutputInfo", err); 02200 } 02201 } else { 02202 rates = (UnsignedFixed *)(*(sil.infoHandle)); 02203 for (i = 0; i < sil.count; i++) { 02204 tmprate = rates[i]; 02205 if (tmprate == sr) 02206 break; 02207 } 02208 DisposeHandle(sil.infoHandle); 02209 02210 if (tmprate != sr) 02211 sr = tmprate; 02212 02213 err = SetSoundOutputInfo(sci, siSampleRate, (void *)sr); 02214 if (err) 02215 jit_object_error((t_object *)x, "jit.qt.movie: error %d SetSoundOutputInfo", err); 02216 02217 for (i = 0; i < x->numaudiotracks; i++) { 02218 err = MediaSetSoundOutputComponent(x->amh[i], sci); 02219 if (err) 02220 jit_object_error((t_object *)x, "jit.qt.movie: error %d MediaSetSoundOutputComponent", err); 02221 } 02222 } 02223 } 02224 02225 if (ComponentFunctionImplemented(x->ci, kQTVideoOutputGetClockSelect)) 02226 QTVideoOutputGetClock(x->ci, &clock); 02227 if (clock) 02228 SetMovieMasterClock(m, (Component)clock, NULL); 02229 } 02230 else if (!qt7) { 02231 for (i = 0; i < x->numaudiotracks; i++) { 02232 MediaSetSoundOutputComponent(x->amh[i], (Component)soc); 02233 } 02234 } 02235 02236 if (x->dw) { 02237 SetMovieGWorld(m, x->dw, NULL); 02238 if (x->moviecontroller) 02239 MCMovieChanged(x->moviecontroller, m); 02240 } 02241 } 02242 else 02243 #endif 02244 { 02245 soc = jit_qt_movie_lookup_soc(x); 02246 //if soc==NULL set anyway to use default component 02247 02248 trackcount = GetMovieTrackCount(m); 02249 x->numaudiotracks = 0; 02250 02251 for (i = 1; i < trackcount + 1; i++) { 02252 track = GetMovieIndTrack(m, i); 02253 media = GetTrackMedia(track); 02254 GetMediaHandlerDescription(media, &type, NULL, NULL); 02255 02256 if (type == SoundMediaType) { 02257 x->amh[x->numaudiotracks] = GetMediaHandler(media); 02258 x->numaudiotracks++; 02259 } 02260 02261 } 02262 if (!qt7) { 02263 for (i = 0; i < x->numaudiotracks; i++) { 02264 err = MediaSetSoundOutputComponent(x->amh[i], (Component)soc); 02265 if (err) jit_object_error((t_object *)x, "jit.qt.movie: error %d setting media soc", err); 02266 } 02267 } 02268 02269 if (qt6) 02270 ChooseMovieClock(m, 0); 02271 else 02272 SetMovieMasterClock(m, (Component)NULL, NULL); 02273 02274 if (jit_qt_movie_window_set(x)) { 02275 ; 02276 } 02277 else if (!x->loadingmovie) { // don't touch the gworld if we're in movie load 02278 SetMovieGWorld(m, x->offscreen, NULL); 02279 SetMovieBox(m, &x->movie_rect); 02280 if (x->moviecontroller) 02281 MCMovieChanged(x->moviecontroller, m); 02282 } 02283 for (i = 0; i < MAX_AUDIO; i++) 02284 x->amh[i] = NULL; 02285 } 02286 02287 // can use x->progress for debugging 02288 SetMovieProgressProc(m, (MovieProgressUPP)0L/*x->progress*/, (long)x); 02289 x->prepped = 1; 02290 return; 02291 } 02292 02293 long jit_qt_movie_ismovie(t_jit_qt_movie *x) 02294 { 02295 if (x->movie || x->tempmovie) 02296 return 1; 02297 else 02298 return 0; 02299 } 02300 02301 Boolean jit_qt_movie_ismpeg(Movie m) 02302 { 02303 Track track; 02304 Media media; 02305 MediaHandler mh; 02306 Boolean isMpeg = false; 02307 02308 if (m) { 02309 if (track = GetMovieIndTrackType(m, 1, kCharacteristicHasVideoFrameRate, movieTrackCharacteristic)) { 02310 if (media = GetTrackMedia(track)) { 02311 if (mh = GetMediaHandler(media)) { 02312 MediaHasCharacteristic(mh, kCharacteristicIsAnMpegTrack, &isMpeg); 02313 return isMpeg; 02314 } 02315 } 02316 } 02317 } 02318 return false; 02319 } 02320 02321 void jit_qt_movie_newmovie(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 02322 { 02323 long width = 320; 02324 long height = 240; 02325 long timescale = 0; 02326 Rect r; 02327 Movie m; 02328 02329 jit_atom_arg_getlong(&width, 0, ac, av); 02330 jit_atom_arg_getlong(&height, 1, ac, av); 02331 jit_atom_arg_getlong(×cale, 2, ac, av); 02332 02333 if (!(width > 0 && height > 0)) 02334 return; 02335 02336 m = NewMovie(newMovieActive); 02337 02338 if (!m) 02339 return; 02340 02341 r.top = 0; 02342 r.left = 0; 02343 r.right = width; 02344 r.bottom = height; 02345 02346 SetMovieBox(m, &r); 02347 if (timescale) 02348 SetMovieTimeScale(m, timescale); 02349 02350 if (x->movie) { 02351 jit_qt_movie_autosave(x); 02352 jit_qt_movie_dispose(x); // dispose gworld NOT inside 02353 jit_qt_movie_dispose_gworld(x); 02354 } 02355 02356 x->movie = m; 02357 x->movie_rect = r; 02358 02359 jit_qt_movie_mreset(x); 02360 jit_qt_movie_movie_prep(x); 02361 02362 x->looppoints[0] = 0; 02363 x->looppoints[1] = GetMovieDuration(x->movie); 02364 if (x->loop != LOOP_OFF) 02365 jit_qt_movie_set_timebase_loop(x); 02366 02367 if (x->autostart) 02368 jit_qt_movie_proxy_method(x, ps_start, 0, NULL); 02369 } 02370 02371 void jit_qt_movie_abort(t_jit_qt_movie *x) 02372 { 02373 if (x->progress) 02374 x->abort = true; 02375 } 02376 02377 // left in place for debugging. however, this doesn't really work properly - percent values are not 02378 // accurate, and the progressProc is only called when the movie is over a certain length. 02379 OSErr jit_qt_movie_progress(Movie movie, short message, short operation, Fixed percent, long refcon) 02380 { 02381 /* t_jit_qt_movie *x = (t_jit_qt_movie *)refcon; 02382 02383 if (operation == progressOpLoadMovieIntoRam || operation == progressOpLoadTrackIntoRam) { 02384 jit_object_post((t_object *)x,"x->abort = %d", x->abort); 02385 switch (message) { 02386 case movieProgressOpen: 02387 jit_object_post((t_object *)x,"loadram starting"); 02388 break; 02389 case movieProgressClose: 02390 jit_object_post((t_object *)x,"loadram stopping"); 02391 break; 02392 case movieProgressUpdatePercent: 02393 jit_object_post((t_object *)x,"loadram %s is %.2f done", (operation == progressOpLoadMovieIntoRam) ? "movie" : "track", FixedToFloat(percent)); 02394 break; 02395 } 02396 if (x->abort) { 02397 jit_object_post((t_object *)x,"aborting"); 02398 x->abort = false; 02399 return abortErr; 02400 } 02401 } */ 02402 return noErr; 02403 } 02404 02405 Movie jit_qt_movie_duplicate_movie(Movie m) 02406 { 02407 Movie mm = NULL; 02408 OSErr err; 02409 02410 if (m) { 02411 /* // this method causes problems with audio tracks under QT7, reverting to old method 02412 // which happens to be faster, too 02413 mm = NewMovie(newMovieActive); // newMovieActive is required, or the movie won't export properly 02414 if (mm) { 02415 StopMovie(mm); 02416 err = InsertMovieSegment(m, mm, 0, GetMovieDuration(m), 0); 02417 if (err) { 02418 jit_object_error((t_object *)x, "jit.qt.movie: %d InsertMovieSegment",err); 02419 DisposeMovie(mm); 02420 mm = NULL; 02421 } 02422 CopyMovieSettings(m, mm); 02423 SetMovieTimeScale(mm, GetMovieTimeScale(m)); 02424 } 02425 else jit_object_error((t_object *)x, "jit.qt.movie: %d NewMovie", GetMoviesError()); 02426 */ 02427 TimeValue selection, duration; 02428 GetMovieSelection(m, &selection, &duration); 02429 if (err = GetMoviesError()) { 02430 // jit_object_error((t_object *)x,"jit.qt.movie: error %d GetMovieSelection", err); 02431 return NULL; 02432 } 02433 SetMovieSelection(m, 0, GetMovieDuration(m)); 02434 if (err = GetMoviesError()) { 02435 // jit_object_error((t_object *)x,"jit.qt.movie: error %d SetMovieSelection", err); 02436 return NULL; 02437 } 02438 mm = CopyMovieSelection(m); 02439 if (!mm) { 02440 // jit_object_error((t_object *)x,"jit.qt.movie: error %d CopyMovieSelection", GetMoviesError()); 02441 return NULL; 02442 } 02443 CopyMovieSettings(m, mm); 02444 SetMovieSelection(m, selection, duration); 02445 } 02446 return mm; 02447 } 02448 // movie_to is always x->movie 02449 void jit_qt_movie_timevalues_convert(t_jit_qt_movie *x, Movie movie_from, long *in_from, long *out_from, Movie movie_to, long *in_to, long *out_to) 02450 { 02451 long iff = 0, of = 0; 02452 long it = 0, ot = 0; 02453 02454 if (in_from) iff = *in_from; 02455 if (out_from) of = *out_from; 02456 if (in_to) it = *in_to; 02457 if (out_to) ot = *out_to; 02458 02459 switch(x->editmode) { 02460 case EDITMODE_FRAME_TRUE: 02461 // these could fail if the supplied values don't exist 02462 if (jit_qt_movie_frame2time_true(x, movie_from, iff, of, in_from, out_from)) 02463 jit_qt_movie_frame2time(x, movie_from, 0, iff, of, in_from, out_from); 02464 if (jit_qt_movie_frame2time_true(x, movie_to, it, ot, in_to, out_to)) 02465 jit_qt_movie_frame2time(x, movie_to, x->fps, it, ot, in_to, out_to); 02466 break; 02467 case EDITMODE_FRAME: 02468 jit_qt_movie_frame2time(x, movie_from, 0, iff, of, in_from, out_from); 02469 jit_qt_movie_frame2time(x, movie_to, x->fps, it, ot, in_to, out_to); 02470 break; 02471 case EDITMODE_MS: 02472 jit_qt_movie_ms2time(x, movie_from, iff, of, in_from, out_from); 02473 jit_qt_movie_ms2time(x, movie_to, it, ot, in_to, out_to); 02474 break; 02475 case EDITMODE_QT: 02476 default: 02477 break; 02478 } 02479 } 02480 02481 t_jit_err jit_qt_movie_frame2time(t_jit_qt_movie *x, Movie m, double fps, long srcin, long dstin, long *srcout, long *dstout) 02482 { 02483 if (x && m && srcout) { 02484 double tsdfps; 02485 02486 if (!fps) { 02487 if (!(fps = jit_qt_movie_moviefps_get(m))) { 02488 unsigned long mt = VideoMediaType; 02489 long id = 0; 02490 long flags = nextTimeMediaSample | nextTimeEdgeOK; 02491 02492 GetMovieNextInterestingTime(m, flags, (TimeValue)1, 02493 &mt, 0, fixed1, NULL, &id); 02494 02495 *srcout = id * srcin; 02496 if (dstout) 02497 *dstout = id * dstin; 02498 return JIT_ERR_NONE; 02499 } 02500 } 02501 tsdfps = (double)GetMovieTimeScale(m) / fps; 02502 *srcout = (long)(tsdfps * srcin); 02503 if (dstout) 02504 *dstout = (long)(tsdfps * dstin); 02505 } 02506 return JIT_ERR_GENERIC; 02507 } 02508 02509 t_jit_err jit_qt_movie_frame2time_true(t_jit_qt_movie *x, Movie m, long srcin, long dstin, long *srcout, long *dstout) 02510 { 02511 if (x && m && srcout) { 02512 TimeBase tb; 02513 TimeRecord tr; 02514 Movie mm; 02515 long scale,dupscale; 02516 02517 if (mm = jit_qt_movie_duplicate_movie(m)) { 02518 tb = GetMovieTimeBase(mm); 02519 GetTimeBaseStartTime(tb, GetMovieTimeScale(mm), &tr); 02520 tr.value.lo = GetMovieDuration(mm); 02521 SetTimeBaseStopTime(tb, &tr); 02522 tr.value.lo = 0; 02523 SetTimeBaseStartTime(tb, &tr); 02524 02525 SetMovieTimeValue(mm, 0); 02526 if (srcout) 02527 *srcout = QTStep_DrawVideoSampleNextOrPrev(x, mm, srcin); 02528 if (dstout) { 02529 SetMovieTimeValue(mm, *srcout); 02530 *dstout = QTStep_DrawVideoSampleNextOrPrev(x, mm, dstin - srcin); 02531 } 02532 DisposeMovie(mm); 02533 return JIT_ERR_NONE; 02534 } 02535 } 02536 return JIT_ERR_GENERIC; 02537 } 02538 02539 t_jit_err jit_qt_movie_ms2time(t_jit_qt_movie *x, Movie m, long srcin, long dstin, long *srcout, long *dstout) 02540 { 02541 if (x && m && srcout) { 02542 *srcout = (long)(GetMovieTimeScale(m) * (srcin * 0.001)); 02543 if (dstout) 02544 *dstout = (long)(GetMovieTimeScale(m) * (dstin * 0.001)); 02545 return JIT_ERR_NONE; 02546 } 02547 return JIT_ERR_GENERIC; 02548 } 02549 02550 // movie_to is always x->movie 02551 void jit_qt_movie_timevalues_convertback(t_jit_qt_movie *x, Movie movie_from, long *in_from, long *out_from, Movie movie_to, long *in_to, long *out_to) 02552 { 02553 long iff = 0, of = 0; 02554 long it = 0, ot = 0; 02555 02556 if (in_from) iff = *in_from; 02557 if (out_from) of = *out_from; 02558 if (in_to) it = *in_to; 02559 if (out_to) ot = *out_to; 02560 02561 switch(x->editmode) { 02562 case EDITMODE_FRAME_TRUE: 02563 // these could fail if the supplied values don't exist 02564 if (jit_qt_movie_time2frame_true(x, movie_from, iff, of, in_from, out_from)) 02565 jit_qt_movie_time2frame(x, movie_from, 0, iff, of, in_from, out_from); 02566 if (jit_qt_movie_time2frame_true(x, movie_to, it, ot, in_to, out_to)) 02567 jit_qt_movie_time2frame(x, movie_to, x->fps, it, ot, in_to, out_to); 02568 break; 02569 case EDITMODE_FRAME: 02570 jit_qt_movie_time2frame(x, movie_from, 0, iff, of, in_from, out_from); 02571 jit_qt_movie_time2frame(x, movie_to, x->fps, it, ot, in_to, out_to); 02572 break; 02573 case EDITMODE_MS: 02574 jit_qt_movie_time2ms(x, movie_from, iff, of, in_from, out_from); 02575 jit_qt_movie_time2ms(x, movie_to, it, ot, in_to, out_to); 02576 break; 02577 case EDITMODE_QT: 02578 default: 02579 break; 02580 } 02581 } 02582 02583 t_jit_err jit_qt_movie_time2frame(t_jit_qt_movie *x, Movie m, double fps, long srcin, long dstin, long *srcout, long *dstout) 02584 { 02585 if (x && m && srcout) { 02586 double tsdfps; 02587 02588 if (!fps) { 02589 if (!(fps = jit_qt_movie_moviefps_get(m))) { 02590 unsigned long mt = VideoMediaType; 02591 long id = 0; 02592 long flags = nextTimeMediaSample | nextTimeEdgeOK; 02593 02594 GetMovieNextInterestingTime(m, flags, (TimeValue)1, 02595 &mt, 0, fixed1, NULL, &id); 02596 02597 *srcout = (id) ? srcin / id : 0; 02598 if (dstout) 02599 *dstout = (id) ? dstin / id : 0; 02600 return JIT_ERR_NONE; 02601 } 02602 } 02603 tsdfps = (double)GetMovieTimeScale(m) / fps; 02604 *srcout = (long)(srcin / tsdfps); 02605 if (dstout) 02606 *dstout = (long)(dstin / tsdfps); 02607 } 02608 return JIT_ERR_GENERIC; 02609 } 02610 02611 long jit_qt_movie_frame_fromtime(t_jit_qt_movie *x, Movie m, long time) 02612 { 02613 TimeValue curtime; 02614 TimeValue nxttime; 02615 short flags; 02616 OSType types[1]; 02617 long i; 02618 02619 if (m == NULL) 02620 return 0; 02621 02622 if (time == 0) 02623 return 0; 02624 02625 i = 0; 02626 flags = nextTimeStep; // we want the next frame in the movie's media 02627 types[0] = VisualMediaCharacteristic; // we want video samples 02628 curtime = GetMovieTime(m, NULL); 02629 02630 while (1) { 02631 GetMovieNextInterestingTime(m, flags, 1, types, curtime, fixed1, &nxttime, NULL); 02632 if (GetMoviesError() != noErr) { // we've reached the end of the movie, probably 02633 if (nxttime == -1) 02634 break; 02635 else return 0; 02636 } 02637 if (nxttime == -1 || time < nxttime) 02638 break; 02639 curtime = nxttime; 02640 i++; 02641 } 02642 return i; 02643 } 02644 02645 t_jit_err jit_qt_movie_time2frame_true(t_jit_qt_movie *x, Movie m, long srcin, long dstin, long *srcout, long *dstout) 02646 { 02647 if (x && m && srcout) { 02648 TimeBase tb; 02649 TimeRecord tr; 02650 Movie mm; 02651 long scale,dupscale; 02652 02653 if (mm = jit_qt_movie_duplicate_movie(m)) { 02654 tb = GetMovieTimeBase(mm); 02655 GetTimeBaseStartTime(tb, GetMovieTimeScale(mm), &tr); 02656 tr.value.lo = GetMovieDuration(mm); 02657 SetTimeBaseStopTime(tb, &tr); 02658 tr.value.lo = 0; 02659 SetTimeBaseStartTime(tb, &tr); 02660 02661 SetMovieTimeValue(mm, 0); 02662 if (srcout) 02663 *srcout = jit_qt_movie_frame_fromtime(x, mm, srcin); 02664 if (dstout) 02665 *dstout = jit_qt_movie_frame_fromtime(x, mm, dstin); 02666 DisposeMovie(mm); 02667 return JIT_ERR_NONE; 02668 } 02669 } 02670 return JIT_ERR_GENERIC; 02671 } 02672 02673 t_jit_err jit_qt_movie_time2ms(t_jit_qt_movie *x, Movie m, long srcin, long dstin, long *srcout, long *dstout) 02674 { 02675 if (x && m && srcout) { 02676 *srcout = (long)(((double)srcin / (double)GetMovieTimeScale(m)) * 1000.); 02677 if (dstout) 02678 *dstout = (long)(((double)dstin / (double)GetMovieTimeScale(m)) * 1000.); 02679 return JIT_ERR_NONE; 02680 } 02681 return JIT_ERR_GENERIC; 02682 } 02683 02684 // note: this doesn't seem to work in a thread 02685 void jit_qt_movie_duplicate(t_jit_qt_movie *x) 02686 { 02687 Movie m; 02688 02689 if (m = jit_qt_movie_duplicate_movie(x->movie)) { 02690 // jit_object_post((t_object *)x,"new movie created with duration %d", GetMovieDuration(m)); 02691 DisposeMovie(m); 02692 } else jit_object_error((t_object *)x, "jit.qt.movie: could not duplicate movie"); 02693 } 02694 02695 void jit_qt_movie_notify_atomarray_prep(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 02696 { 02697 if (ac && av) { 02698 t_object *arr; 02699 t_atom *a; 02700 02701 if (a = (t_atom *)sysmem_newptr(sizeof(t_atom) * (ac + 1))) { 02702 jit_atom_setsym(a, s); 02703 sysmem_copyptr(av, a + 1, sizeof(t_atom) * ac); 02704 arr = (t_object *)object_new(ps_nobox, ps_atomarray, ac + 1, a); 02705 jit_object_notify(x, ps_typedmess, arr); 02706 freeobject(arr); 02707 sysmem_freeptr(a); 02708 } 02709 } 02710 else jit_object_notify(x, s, NULL); 02711 } 02712 02713 void jit_qt_movie_unloadram_completion(t_jit_qt_movie *x) 02714 { 02715 if (x->movie) { 02716 OSErr err; 02717 02718 #ifdef MAC_VERSION 02719 if (qt64) { 02720 DEBUGPOST(("attaching in unloadram_completion")); 02721 mAttachMovieToCurrentThread(x->movie); 02722 } 02723 #endif 02724 } 02725 } 02726 02727 Boolean jit_qt_movie_window_set(t_jit_qt_movie *x) 02728 { 02729 void *jw; 02730 void *mw; // jpatcher window, HWND or WindowRef 02731 WindowPtr w; 02732 Rect r; 02733 02734 if (x->window != _jit_sym_nothing && 02735 (jw = jit_object_findregistered(x->window)) && 02736 (jit_object_method(jw, ps_class_jit_window))) 02737 { 02738 jit_object_method(jw, ps_get_window_ptr, &mw); 02739 if (mw) { 02740 #ifdef WIN_VERSION 02741 if (!(w = GetNativeWindowPort(mw))) { // already attached 02742 CreatePortAssociation(mw, NULL, 0L); 02743 w = GetNativeWindowPort(mw); 02744 } 02745 #else 02746 w = mw; 02747 #endif 02748 02749 if (w) { 02750 #ifdef WIN_VERSION 02751 SetMovieGWorld(x->movie, (CGrafPtr)w, GetGWorldDevice((GWorldPtr)w)); 02752 GetPortBounds((CGrafPtr)w, &r); 02753 #else 02754 SetMovieGWorld(x->movie, GetWindowPort(w), GetGWorldDevice(GetWindowPort(w))); 02755 GetWindowPortBounds((WindowRef)w, &r); 02756 #endif 02757 SetMovieBox(x->movie, &r); 02758 if (x->moviecontroller) 02759 MCMovieChanged(x->moviecontroller, x->movie); 02760 } 02761 } else { 02762 SetMovieGWorld(x->movie, x->offscreen, NULL); 02763 SetMovieBox(x->movie, &x->movie_rect); 02764 if (x->moviecontroller) 02765 MCMovieChanged(x->moviecontroller, x->movie); 02766 } 02767 return true; 02768 } 02769 return false; 02770 } 02771 02772 void jit_qt_movie_loadram_completion(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 02773 { 02774 if (ac && av) { 02775 OSErr err; 02776 Movie m = (Movie)atom_getobj(av); 02777 02778 if (m != x->movie) { 02779 DEBUGPOST(("wrong movie in loadram_completion")); 02780 return; 02781 } 02782 02783 #ifdef MAC_VERSION 02784 if (qt64) { 02785 DEBUGPOST(("attaching in loadram_completion")); 02786 mAttachMovieToCurrentThread(x->movie); 02787 } 02788 #endif 02789 if (x->mode) { 02790 SetMovieGWorld(x->movie, x->dw, NULL); 02791 if (x->moviecontroller) 02792 MCMovieChanged(x->moviecontroller, x->movie); 02793 } else 02794 jit_qt_movie_window_set(x); 02795 } 02796 } 02797 02798 void jit_qt_movie_doloadram(t_jit_qt_movie *x, t_thread_loadram_info *ti) 02799 { 02800 long ac = ti->ac; 02801 long from = ti->from; 02802 long to = ti->to; 02803 long trackid = ti->trackid; 02804 char threaded = ti->threaded; 02805 long err; 02806 Track track; 02807 t_atom a; 02808 Movie m = NULL; 02809 02810 if (ti->m != x->movie) 02811 DEBUGPOST(("wrong movie in doloadram")); 02812 02813 if (x->movie && ti->m == x->movie) { 02814 m = x->movie; 02815 #ifdef MAC_VERSION 02816 if (threaded) { 02817 if (qt64) { 02818 DEBUGPOST(("attaching in doloadram")); 02819 mAttachMovieToCurrentThread(m); 02820 } 02821 } 02822 #endif 02823 // x->progress = NewMovieProgressUPP((MovieProgressProcPtr)jit_qt_movie_progress); 02824 // SetMovieProgressProc(m, (MovieProgressUPP)x->progress, (long)x); 02825 jit_atom_setlong(&a, 0L); 02826 switch(ac) { 02827 case 0: 02828 case 2: 02829 if (!(from || to)) { 02830 if (!(err = LoadMovieIntoRam(m, 0, GetMovieDuration(m), keepInRam))) 02831 jit_atom_setlong(&a, 1L); 02832 } 02833 else { 02834 CLIP(to, 0, GetMovieDuration(m)); 02835 CLIP(from, 0, GetMovieDuration(m)); 02836 if (from > to) { 02837 long temp = to; 02838 02839 to = from; 02840 from = temp; 02841 } 02842 if (!(err = LoadMovieIntoRam(m, from, to - from, keepInRam))) 02843 jit_atom_setlong(&a, 1L); 02844 } 02845 break; 02846 case 1: 02847 case 3: 02848 default: 02849 track = GetMovieIndTrack(m, trackid); 02850 if (!(from || to)) { 02851 if (!(err = LoadTrackIntoRam(track, 0, GetTrackDuration(track), keepInRam))) 02852 jit_atom_setlong(&a, 1L); 02853 } 02854 else { 02855 CLIP(to, 0, GetTrackDuration(track)); 02856 CLIP(from, 0, GetTrackDuration(track)); 02857 if (from > to) { 02858 long temp = to; 02859 02860 to = from; 02861 from = temp; 02862 } 02863 if (!(err = LoadTrackIntoRam(track, from, to-from, keepInRam))) 02864 jit_atom_setlong(&a, 1L); 02865 } 02866 break; 02867 } 02868 if (ti->report) 02869 defer_low(x, (method)jit_qt_movie_notify_atomarray_prep, ps_loadram, 1, &a); 02870 02871 // SetMovieProgressProc(m, (MovieProgressUPP)NULL, (long)x); 02872 // DisposeMovieProgressUPP(x->progress); 02873 // x->progress = NULL; 02874 } 02875 sysmem_freeptr(ti); 02876 if (m && threaded) { 02877 t_atom a; 02878 #ifdef MAC_VERSION 02879 if (qt64) { 02880 DEBUGPOST(("detaching in doloadram")); 02881 mDetachMovieFromCurrentThread(m); 02882 } 02883 #endif 02884 atom_setobj(&a, m); 02885 defer_low(x, (method)jit_qt_movie_loadram_completion, NULL, 1, &a); 02886 } 02887 } 02888 02889 void jit_qt_movie_unloadram_cached(t_jit_qt_movie *x) 02890 { 02891 if (x->movie && x->cached) { // cannot be threaded, for some reason. causes crashing. 02892 LoadMovieIntoRam(x->movie, 0, GetMovieDuration(x->movie), flushFromRam); // free it all - we don't know how much is loaded 02893 x->cached = false; 02894 } 02895 } 02896 02897 /* 02898 #ifdef MAC_VERSION 02899 if (qt64) { 02900 mDetachMovieFromCurrentThread(x->movie); 02901 } 02902 #endif 02903 x->workerinfo.m = (method)jit_qt_movie_dounloadram_cached; 02904 x->workerinfo.data = NULL; 02905 systhread_cond_signal(x->workercond); 02906 } 02907 void jit_qt_movie_dounloadram_cached(t_jit_qt_movie *x) 02908 { 02909 if (x->movie && x->cached) { 02910 #ifdef MAC_VERSION 02911 if (qt64) { 02912 mAttachMovieToCurrentThread(x->movie); 02913 } 02914 #endif 02915 02916 LoadMovieIntoRam(x->movie, 0, GetMovieDuration(x->movie), flushFromRam); // free it all - we don't know how much is loaded 02917 02918 #ifdef MAC_VERSION 02919 if (qt64) { 02920 mDetachMovieFromCurrentThread(x->movie); 02921 } 02922 #endif 02923 02924 defer_low(x, (method)jit_qt_movie_unloadram_completion, NULL, 0, NULL); 02925 x->cached = false; 02926 } 02927 } 02928 */ 02929 02930 long jit_qt_movie_loadram(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 02931 { 02932 long from = 0, to = 0; 02933 long trackid = 0; 02934 OSErr err = 0; 02935 02936 // 1 arg = track 02937 // 2 args = movie w/ start, end 02938 // 3 args = track w/ start, end 02939 if (x->movie) { 02940 t_thread_loadram_info *ti = (t_thread_loadram_info *)sysmem_newptr(sizeof(t_thread_loadram_info)); 02941 02942 ti->x = x; 02943 ti->ac = ac; 02944 switch(ac) { 02945 case 0: 02946 case 2: 02947 jit_atom_arg_getlong(&from, 0, ac, av); 02948 jit_atom_arg_getlong(&to, 1, ac, av); 02949 break; 02950 default: 02951 jit_atom_arg_getlong(&trackid, 0, ac, av); 02952 jit_atom_arg_getlong(&from, 1, ac, av); 02953 jit_atom_arg_getlong(&to, 2, ac, av); 02954 break; 02955 } 02956 jit_qt_movie_timevalues_convert(x, x->movie, &from, &to, NULL, NULL, NULL); 02957 ti->m = x->movie; 02958 ti->from = from; 02959 ti->to = to; 02960 ti->trackid = trackid; 02961 ti->report = true; 02962 #ifdef MAC_VERSION 02963 if (qt64) { 02964 // mDetachTimeBaseFromCurrentThread(GetMovieTimeBase(x->movie)); 02965 DEBUGPOST(("detaching in loadram")); 02966 err = mDetachMovieFromCurrentThread(x->movie); 02967 } 02968 if (!err) 02969 #else 02970 if (1) 02971 #endif 02972 { 02973 ti->threaded = true; 02974 x->workerinfo.m = (method)jit_qt_movie_doloadram; 02975 x->workerinfo.data = ti; 02976 systhread_cond_signal(x->workercond); 02977 } 02978 else { 02979 ti->threaded = false; 02980 jit_qt_movie_doloadram(x, ti); 02981 // jit_object_post((t_object *)x,"error %d detaching from mainthread", err); 02982 } 02983 } 02984 return JIT_ERR_NONE; 02985 } 02986 02987 long jit_qt_movie_loadram_internal(t_jit_qt_movie *x, long from, long to, long trackid) 02988 { 02989 if (x->movie) { 02990 t_thread_loadram_info *ti = (t_thread_loadram_info *)sysmem_newptr(sizeof(t_thread_loadram_info)); 02991 OSErr err = 0; 02992 02993 ti->x = x; 02994 ti->m = x->movie; 02995 if (trackid == -1) 02996 ti->ac = 2; 02997 else 02998 ti->ac = 3; 02999 03000 ti->from = from; 03001 ti->to = to; 03002 ti->report = false; 03003 03004 jit_qt_movie_disposecallback(x, NULL, 0, NULL); 03005 x->restoreloop = true; 03006 03007 #ifdef MAC_VERSION 03008 if (qt64) { 03009 if (x->mode || x->window != _jit_sym_nothing) { 03010 SetMovieGWorld(x->movie, NULL, NULL); 03011 if (x->moviecontroller) 03012 MCMovieChanged(x->moviecontroller, x->movie); 03013 } 03014 DEBUGPOST(("detaching in loadram_internal")); 03015 err = mDetachMovieFromCurrentThread(x->movie); 03016 } 03017 if (!err) 03018 #else 03019 if (1) 03020 #endif 03021 { 03022 ti->threaded = true; 03023 x->cached = true; // only mark cached in this instance 03024 x->workerinfo.m = (method)jit_qt_movie_doloadram; 03025 x->workerinfo.data = ti; 03026 systhread_cond_signal(x->workercond); 03027 } 03028 else { 03029 DEBUGPOST(("error %d detaching from mainthread", err)); 03030 if (x->mode) { 03031 SetMovieGWorld(x->movie, x->dw, NULL); 03032 if (x->moviecontroller) 03033 MCMovieChanged(x->moviecontroller, x->movie); 03034 } 03035 sysmem_freeptr(ti); 03036 } 03037 } 03038 03039 return JIT_ERR_NONE; 03040 } 03041 03042 // this causes a hiccup in sound playback. may just be how it is. 03043 void jit_qt_movie_unloadram(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 03044 { 03045 OSErr err = noErr; 03046 Track track = NULL; 03047 long trackid = 0; 03048 long from = 0, to = 0; 03049 t_atom a; 03050 03051 jit_atom_setlong(&a, 0L); 03052 if (x->movie) { 03053 switch(ac) { 03054 case 0: 03055 case 2: 03056 jit_atom_arg_getlong(&from, 0, ac, av); 03057 jit_atom_arg_getlong(&to, 1, ac, av); 03058 jit_qt_movie_timevalues_convert(x, x->movie, &from, &to, NULL, NULL, NULL); 03059 if (!(from || to)) { 03060 if (!(err = LoadMovieIntoRam(x->movie, 0, GetMovieDuration(x->movie), unkeepInRam))) 03061 jit_atom_setlong(&a, 1L); 03062 } 03063 else { 03064 CLIP(to, 0, GetMovieDuration(x->movie)); 03065 CLIP(from, 0, GetMovieDuration(x->movie)); 03066 if (from > to) { 03067 long temp = to; 03068 03069 to = from; 03070 from = temp; 03071 } 03072 if (!(err = LoadMovieIntoRam(x->movie, from, to - from, unkeepInRam))) 03073 jit_atom_setlong(&a, 1L); 03074 } 03075 break; 03076 case 1: 03077 case 3: 03078 default: 03079 jit_atom_arg_getlong(&trackid, 0, ac, av); 03080 jit_atom_arg_getlong(&from, 1, ac, av); 03081 jit_atom_arg_getlong(&to, 2, ac, av); 03082 jit_qt_movie_timevalues_convert(x, x->movie, &from, &to, NULL, NULL, NULL); 03083 track = GetMovieIndTrack(x->movie, trackid); 03084 if (!(from || to)) { 03085 if (!(err = LoadTrackIntoRam(track, 0, GetTrackDuration(track), unkeepInRam))) 03086 jit_atom_setlong(&a, 1L); 03087 } 03088 else { 03089 CLIP(to, 0, GetTrackDuration(track)); 03090 CLIP(from, 0, GetTrackDuration(track)); 03091 if (from > to) { 03092 long temp = to; 03093 03094 to = from; 03095 from = temp; 03096 } 03097 if (!(err = LoadTrackIntoRam(track, from, to-from, unkeepInRam))) 03098 jit_atom_setlong(&a, 1L); 03099 } 03100 break; 03101 } 03102 } 03103 jit_qt_movie_notify_atomarray_prep(x, ps_unloadram, 1, &a); 03104 return; 03105 } 03106 03107 #pragma mark - 03108 #pragma mark asynch load 03109 #pragma mark - 03110 03111 // jb 050425 changed, now only active if a movie is stopped. once it gets started, _start takes over, if the movie hasn't completed loading 03112 void jit_qt_movie_progdl(t_jit_qt_movie *x) 03113 { 03114 TimeValue time; 03115 03116 if (x->movie && x->progdl) { 03117 #ifndef TASKTEST 03118 jit_qt_movie_task(x); 03119 #endif 03120 GetMaxLoadedTimeInMovie(x->movie, &time); 03121 if (time != GetMovieDuration(x->movie)) 03122 qelem_set(x->progdl_qelem); 03123 } 03124 } 03125 03126 void jit_qt_movie_unloadram_clockfn(t_jit_qt_movie *x) 03127 { 03128 defer_low(x, (method)jit_qt_movie_proxy_method, ps_unloadram_cached, 0, NULL); 03129 } 03130 03131 void jit_qt_movie_dopreprecomplete(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) //Movie movie, OSErr err, void *s) 03132 { 03133 OSErr err = (OSErr)jit_atom_getlong(av); 03134 Movie movie = (Movie)jit_atom_getobj(av + 1); 03135 TimeValue time; 03136 03137 if (movie != x->movie) { 03138 // jit_object_error((t_object *)x, "movie backlog %x != %x", movie, x->movie); 03139 return; 03140 } 03141 if (err == noErr) { 03142 Fixed playRate; 03143 03144 playRate = FloatToFixed(x->rate); 03145 time = GetMovieTime(movie, NULL); 03146 PrerollMovie(movie, time, playRate); 03147 jit_qt_movie_movierate_set(x, movie, x->rate); 03148 if (x->cached == true) { 03149 #ifdef TEST 03150 /* 03151 There seem to be 2 scenarios here, apropos sound track media sample durations 03152 1. dur != 1, rettime != time (necessarily) && retnum == 1; in this case, we want to know when we've reached rettime + dur. 03153 2. dur == 1, rettime == time && retnum indicates a diminishing number of samples, until a new "group" is begun. To know the size of the group, 03154 I think we have to take a media sample at time 0. 03155 03156 In either case, taking a media sample at time 0 might be smart. Then, we can ballpark a "safe" distance after restarting to free the Ram. 03157 This, of course, assumes that my theory is correct: that we crash because unloadram is freeing in-use memory. All work so far would indicate this. 03158 This seems haphazard, but not so haphazard as just waiting 5 seconds. We should maybe call the clock for 5 seconds, and check if the unsafe time has passed? 03159 We could also set a QTcallback to do this. Callback at (sample group size * 5) or something, to be sure. Requires a little more setup, but might be less hackerific than what we have now. 03160 */ 03161 { 03162 Track track = GetMovieIndTrackType(x->movie, 1, SoundMediaType, movieTrackMediaType); 03163 Media media = GetTrackMedia(track); 03164 TimeValue rettime, dur; 03165 long retnum, offs; 03166 03167 GetMediaSampleReference(media, &offs, NULL, time, &rettime, &dur, NULL, NULL, 0, &retnum, NULL); 03168 jit_object_post((t_object *)x,"%d: got %d (%d long each), total of %d", time, rettime, dur, retnum); 03169 } 03170 #endif 03171 clock_unset(x->unloadram_clock); 03172 clock_delay(x->unloadram_clock, 5000); // completely arbitrary - should do something a little better 03173 // but there's no way to find out what a "chunk" of the audio track is 03174 // defer_low(x, (method)jit_qt_movie_proxy_method, ps_unloadram_cached, 0, NULL); 03175 } 03176 } 03177 else { 03178 jit_object_error((t_object *)x, "jit.qt.movie: network error %d", err); 03179 } 03180 } 03181 03182 void jit_qt_movie_preprecomplete(Movie movie, OSErr err, void *s) 03183 { 03184 t_atom a[2]; 03185 t_jit_qt_movie *x = s; 03186 03187 jit_atom_setlong(&a[0], err); 03188 jit_atom_setobj(&a[1], movie); 03189 defer_low(x, (method)jit_qt_movie_dopreprecomplete, 0L, 2, a); 03190 } 03191 03192 #pragma mark - 03193 #pragma mark startstoplocate 03194 #pragma mark - 03195 03196 long jit_qt_movie_start(t_jit_qt_movie *x) 03197 { 03198 TimeValue timeNow; 03199 Fixed playRate; 03200 Boolean here = true, anywhere; 03201 03202 if (x->movie) { 03203 if (GetMovieLoadState(x->movie) < kMovieLoadStatePlaythroughOK) { 03204 qelem_unset(x->progdl_qelem); 03205 qelem_set(x->start_qelem); 03206 #ifndef TASKTEST 03207 jit_qt_movie_task(x); 03208 #endif 03209 return JIT_ERR_NONE; 03210 } 03211 // moved this after the loadstate stuff, to ensure that the movie gets tasked, if it's still loading 03212 if (GetMovieRate(x->movie)) { 03213 return JIT_ERR_NONE; 03214 } 03215 03216 timeNow = GetMovieTime(x->movie, nil); 03217 playRate = FloatToFixed(x->rate); 03218 03219 PrePrerollMovie(x->movie, timeNow, playRate, x->prepre, (void *)x); 03220 return JIT_ERR_NONE; 03221 } 03222 else { 03223 return JIT_ERR_GENERIC; 03224 } 03225 } 03226 03227 void jit_qt_movie_stop(t_jit_qt_movie *x) 03228 { 03229 jit_qt_movie_proxy_method(x, ps_stop, 0, NULL); 03230 } 03231 03232 long jit_qt_movie_stop2(t_jit_qt_movie *x, t_symbol *s) 03233 { 03234 Fixed rate; 03235 TimeValue from, to; 03236 TimeScale timescale; 03237 03238 if (x->movie) { 03239 rate = GetMovieRate(x->movie); 03240 03241 if (!rate) { 03242 if (SPIGOTTED) 03243 ; 03244 else if (s != ps_asyncstop) // we force when asyncreading 03245 return JIT_ERR_NONE; 03246 } 03247 03248 StopMovie(x->movie); 03249 jit_qt_movie_soc_rate_set(x, 0); 03250 /////////// disabled to improve hiccup 03251 // jit_qt_movie_task(x); // otherwise extra frame happens 03252 03253 if (!x->bframe && /*x->window == _jit_sym_nothing &&*/ ((x->optimize && x->preroll) || s == ps_asyncstop)) { 03254 // the movie toolkit allocates RAM as it sees fit, so why bother with anything more complex? 03255 from = GetMovieTime(x->movie, NULL); 03256 to = from + 1; 03257 from = (from - 1 < 0) ? 0 : from - 1; 03258 03259 clock_unset(x->unloadram_clock); 03260 jit_qt_movie_loadram_internal(x, from, to, -1); // preload next bit */ 03261 } 03262 return JIT_ERR_NONE; 03263 } else { 03264 return JIT_ERR_GENERIC; 03265 } 03266 } 03267 03268 void jit_qt_movie_movierate_set(t_jit_qt_movie *x, Movie m, double rate) 03269 { 03270 if (SPIGOTTED) 03271 jit_qt_movie_soc_rate_set(x, rate); 03272 else 03273 SetMovieRate(m, DoubleToFixed(rate)); 03274 } 03275 03276 long jit_qt_movie_jump(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 03277 { 03278 if (x->movie) { 03279 if (!x->fps) { 03280 if (!(x->fps = jit_attr_getfloat(x, ps_fps))) { 03281 unsigned long mt = VideoMediaType; 03282 long id = 0; 03283 long flags = nextTimeMediaSample | nextTimeEdgeOK; 03284 03285 GetMovieNextInterestingTime(x->movie, flags, (TimeValue)1, 03286 &mt, 0, fixed1, NULL, &id); 03287 jit_qt_movie_setmovietimevalue(x, x->movie, GetMovieTime(x->movie, NULL) + (id * jit_atom_getlong(av))); 03288 // SetMovieTimeValue(x->movie, GetMovieTime(x->movie, NULL) + (id * jit_atom_getlong(av))); 03289 // x->restoreloop = true; 03290 return JIT_ERR_NONE; 03291 } 03292 } 03293 jit_qt_movie_setmovietimevalue(x, x->movie, GetMovieTime(x->movie, NULL) + (long)(((double)GetMovieTimeScale(x->movie) / x->fps) * jit_atom_getlong(av))); 03294 // SetMovieTimeValue(x->movie, GetMovieTime(x->movie, NULL) + (long)(((double)GetMovieTimeScale(x->movie) / x->fps) * jit_atom_getlong(av))); 03295 03296 // if (x->loop) 03297 // x->restoreloop = true; 03298 03299 return JIT_ERR_NONE; 03300 } 03301 else { 03302 return JIT_ERR_GENERIC; 03303 } 03304 } 03305 03306 long jit_qt_movie_jump_true(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 03307 { 03308 if (x->movie) { 03309 TimeBase tb; 03310 TimeRecord tr; 03311 Movie mm; 03312 03313 if (jit_qt_movie_ismpeg(x->movie)) { 03314 return jit_qt_movie_jump(x, s, ac, av); 03315 } 03316 if (mm = jit_qt_movie_duplicate_movie(x->movie)) { 03317 tb = GetMovieTimeBase(mm); 03318 GetTimeBaseStartTime(tb, GetMovieTimeScale(mm), &tr); 03319 tr.value.lo = GetMovieDuration(mm); 03320 SetTimeBaseStopTime(tb, &tr); 03321 tr.value.lo = 0; 03322 SetTimeBaseStartTime(tb, &tr); 03323 SetMovieTimeValue(mm, GetMovieTime(x->movie, NULL)); 03324 jit_qt_movie_setmovietimevalue(x, x->movie, QTStep_DrawVideoSampleNextOrPrev(x, mm, jit_atom_getlong(av))); 03325 // SetMovieTimeValue(x->movie, QTStep_DrawVideoSampleNextOrPrev(x, mm, jit_atom_getlong(av))); 03326 DisposeMovie(mm); 03327 return JIT_ERR_NONE; 03328 } 03329 } 03330 return JIT_ERR_GENERIC; 03331 } 03332 03333 long jit_qt_movie_frame(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 03334 { 03335 if (x->movie) { 03336 if (!x->fps) { 03337 if (!(x->fps = jit_attr_getfloat(x, ps_fps))) { 03338 unsigned long mt = VideoMediaType; 03339 long id = 0; 03340 long flags = nextTimeMediaSample | nextTimeEdgeOK; 03341 03342 GetMovieNextInterestingTime(x->movie, flags, (TimeValue)1, 03343 &mt, 0, fixed1, NULL, &id); 03344 jit_qt_movie_setmovietimevalue(x, x->movie, id * jit_atom_getlong(av)); 03345 // SetMovieTimeValue(x->movie, id * jit_atom_getlong(av)); 03346 // x->restoreloop = true; 03347 return JIT_ERR_NONE; 03348 } 03349 } 03350 jit_qt_movie_setmovietimevalue(x, x->movie, (long)(((double)GetMovieTimeScale(x->movie) / x->fps) * jit_atom_getlong(av))); 03351 // SetMovieTimeValue(x->movie, (long)(((double)GetMovieTimeScale(x->movie) / x->fps) * jit_atom_getlong(av))); 03352 03353 // if (x->loop) 03354 // x->restoreloop = true; 03355 03356 return JIT_ERR_NONE; 03357 } 03358 else { 03359 return JIT_ERR_GENERIC; 03360 } 03361 } 03362 03363 long jit_qt_movie_frame_true(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 03364 { 03365 if (x->movie) { 03366 TimeBase tb; 03367 TimeRecord tr; 03368 Movie mm; 03369 03370 if (jit_qt_movie_ismpeg(x->movie)) { 03371 return jit_qt_movie_frame(x, s, ac, av); 03372 } 03373 if (mm = jit_qt_movie_duplicate_movie(x->movie)) { 03374 tb = GetMovieTimeBase(mm); 03375 GetTimeBaseStartTime(tb, GetMovieTimeScale(mm), &tr); 03376 tr.value.lo = GetMovieDuration(mm); 03377 SetTimeBaseStopTime(tb, &tr); 03378 tr.value.lo = 0; 03379 SetTimeBaseStartTime(tb, &tr); 03380 SetMovieTimeValue(mm, 0); 03381 jit_qt_movie_setmovietimevalue(x, x->movie, QTStep_DrawVideoSampleNextOrPrev(x, mm, jit_atom_getlong(av))); 03382 // SetMovieTimeValue(x->movie, QTStep_DrawVideoSampleNextOrPrev(x, mm, jit_atom_getlong(av))); 03383 DisposeMovie(mm); 03384 return JIT_ERR_NONE; 03385 } 03386 } 03387 return JIT_ERR_GENERIC; 03388 } 03389 03390 #pragma mark - 03391 #pragma mark looping 03392 #pragma mark - 03393 03394 void jit_qt_movie_restoreloop(t_jit_qt_movie *x) 03395 { 03396 if (x->movie && x->looppoints[1]) { 03397 TimeBase tb; 03398 TimeRecord tr; 03399 03400 tb = GetMovieTimeBase(x->movie); 03401 if (x->loop != LOOP_OFF) { 03402 GetTimeBaseStartTime(tb, GetMovieTimeScale(x->movie), &tr); // fill out struct 03403 03404 tr.value.lo = x->looppoints[0]; 03405 SetTimeBaseStartTime(tb, &tr); 03406 tr.value.lo = x->looppoints[1]; 03407 SetTimeBaseStopTime(tb, &tr); 03408 } 03409 03410 if (!x->cb) { 03411 x->cb = NewCallBack(tb, callBackAtExtremes);//callBackAtTime); 03412 jit_qt_movie_callback_setup(x, x->cb, true); 03413 } 03414 } 03415 x->restoreloop = false; 03416 } 03417 03418 void jit_qt_movie_loop(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 03419 { 03420 x->loop = jit_atom_getlong(av); 03421 CLIP(x->loop, LOOP_OFF, LOOP_SINGLEPLAYSELECTION); 03422 03423 if (x->use_movie_loop) { 03424 if (x->movie) { //add/remove loop atom 03425 UserData ud; 03426 short c; 03427 char insert = false; 03428 03429 ud = GetMovieUserData(x->movie); 03430 c = CountUserDataType(ud, FOUR_CHAR_CODE('LOOP')); 03431 while (c--) 03432 RemoveUserData(ud, FOUR_CHAR_CODE('LOOP'), 1); 03433 if (x->loop) { 03434 long loop; 03435 03436 switch(x->loop) { 03437 case LOOP_ON: loop = 0; insert = true; break; 03438 case LOOP_PALINDROME: loop = 1; insert = true; break; 03439 case LOOP_OFF: 03440 case LOOP_SINGLEPLAYSELECTION: 03441 loop = 2; 03442 insert = false; // we're not going to insert, anyway 03443 break; 03444 } 03445 if (insert) { 03446 Handle h = NewHandle(sizeof(long)); 03447 (** (long **) h) = loop; 03448 AddUserData(ud, h, FOUR_CHAR_CODE('LOOP')); 03449 DisposeHandle(h); 03450 } 03451 } 03452 } 03453 } 03454 jit_qt_movie_set_timebase_loop(x); 03455 } 03456 03457 void jit_qt_movie_loopstart(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 03458 { 03459 long tmp; 03460 long lp; 03461 03462 if (!x->movie) 03463 return; 03464 03465 jit_atom_arg_getlong(&lp, 0, ac, av); 03466 jit_qt_movie_timevalues_convert(x, x->movie, &lp, NULL, NULL, NULL, NULL); 03467 03468 x->looppoints[0] = MAX(lp, 0); 03469 if (x->looppoints[0] > x->looppoints[1]) { 03470 tmp = x->looppoints[0]; 03471 x->looppoints[0] = x->looppoints[1]; 03472 x->looppoints[1] = tmp; 03473 } 03474 03475 if (x->loop != LOOP_OFF) 03476 jit_qt_movie_set_timebase_loop(x); 03477 } 03478 03479 void jit_qt_movie_loopend(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 03480 { 03481 long tmp; 03482 long lp; 03483 03484 if (!x->movie) 03485 return; 03486 03487 lp = GetMovieDuration(x->movie); 03488 jit_atom_arg_getlong(&lp, 0, ac, av); 03489 jit_qt_movie_timevalues_convert(x, x->movie, &lp, NULL, NULL, NULL, NULL); 03490 03491 x->looppoints[1] = MAX(lp, 0); 03492 03493 if (x->looppoints[0] > x->looppoints[1]) { 03494 tmp = x->looppoints[0]; 03495 x->looppoints[0] = x->looppoints[1]; 03496 x->looppoints[1] = tmp; 03497 } 03498 03499 if (x->loop != LOOP_OFF) 03500 jit_qt_movie_set_timebase_loop(x); 03501 } 03502 03503 void jit_qt_movie_looppoints(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 03504 { 03505 long tmp; 03506 long lp1, lp2; 03507 03508 if (!x->movie) 03509 return; 03510 03511 lp1 = 0; 03512 lp2 = GetMovieDuration(x->movie); 03513 03514 jit_atom_arg_getlong(&lp1, 0, ac, av); 03515 jit_atom_arg_getlong(&lp2, 1, ac, av); 03516 jit_qt_movie_timevalues_convert(x, x->movie, &lp1, &lp2, NULL, NULL, NULL); 03517 03518 x->looppoints[0] = MAX(lp1, 0); 03519 x->looppoints[1] = MAX(lp2, 0); 03520 03521 if (x->looppoints[0] > x->looppoints[1]) { 03522 tmp = x->looppoints[0]; 03523 x->looppoints[0] = x->looppoints[1]; 03524 x->looppoints[1] = tmp; 03525 } 03526 03527 if (x->loop != LOOP_OFF) 03528 jit_qt_movie_set_timebase_loop(x); 03529 } 03530 03531 t_jit_err jit_qt_movie_looppoints_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 03532 { 03533 long tmp; 03534 long lp1, lp2; 03535 03536 if (x->movie && ac && av) { 03537 if ((*ac) && (*av)) { 03538 ; 03539 } 03540 else { 03541 *ac = 2; 03542 *av = (t_atom *)jit_getbytes(sizeof(t_atom) * (*ac)); 03543 if (!(*av)) { 03544 *ac = 0; 03545 return JIT_ERR_OUT_OF_MEM; 03546 } 03547 } 03548 lp1 = x->looppoints[0]; 03549 lp2 = x->looppoints[1]; 03550 03551 jit_qt_movie_timevalues_convertback(x, x->movie, &lp1, &lp2, NULL, NULL, NULL); 03552 03553 jit_atom_setlong(*av, lp1); 03554 jit_atom_setlong(*av + 1, lp2); 03555 } 03556 return JIT_ERR_NONE; 03557 } 03558 03559 t_jit_err jit_qt_movie_loopstart_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 03560 { 03561 long tmp; 03562 long lp1, lp2; 03563 03564 if (x->movie && ac && av) { 03565 if ((*ac) && (*av)) { 03566 ; 03567 } 03568 else { 03569 *ac = 1; 03570 *av = (t_atom *)jit_getbytes(sizeof(t_atom) * (*ac)); 03571 if (!(*av)) { 03572 *ac = 0; 03573 return JIT_ERR_OUT_OF_MEM; 03574 } 03575 } 03576 lp1 = x->looppoints[0]; 03577 03578 jit_qt_movie_timevalues_convertback(x, x->movie, &lp1, NULL, NULL, NULL, NULL); 03579 03580 jit_atom_setlong(*av, lp1); 03581 } 03582 return JIT_ERR_NONE; 03583 } 03584 03585 t_jit_err jit_qt_movie_loopend_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 03586 { 03587 long tmp; 03588 long lp2; 03589 03590 if (x->movie && ac && av) { 03591 if ((*ac) && (*av)) { 03592 ; 03593 } 03594 else { 03595 *ac = 1; 03596 *av = (t_atom *)jit_getbytes(sizeof(t_atom) * (*ac)); 03597 if (!(*av)) { 03598 *ac = 0; 03599 return JIT_ERR_OUT_OF_MEM; 03600 } 03601 } 03602 lp2 = x->looppoints[1]; 03603 03604 jit_qt_movie_timevalues_convertback(x, x->movie, &lp2, NULL, NULL, NULL, NULL); 03605 03606 jit_atom_setlong(*av, lp2); 03607 } 03608 return JIT_ERR_NONE; 03609 } 03610 03611 void jit_qt_movie_disposecallback(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 03612 { 03613 if (x->cb) { 03614 CancelCallBack(x->cb); 03615 DisposeCallBack(x->cb); 03616 x->cb = 0; 03617 } 03618 } 03619 03620 void jit_qt_movie_looper_notify(t_jit_qt_movie *x) 03621 { 03622 jit_object_notify(x, ps_loopreport, 0L); 03623 } 03624 03625 pascal void jit_qt_movie_looper(QTCallBack cb, long ref) 03626 { 03627 t_jit_qt_movie *x = (t_jit_qt_movie *)ref; 03628 TimeBase tb; 03629 TimeValue ctime; 03630 float frate; 03631 03632 if (x->movie) { 03633 #ifdef MAC_VERSION 03634 if (qt64) { 03635 Boolean here, anywhere; 03636 03637 mGetMovieThreadAttachState(x->movie, &here, &anywhere); 03638 if (!here) { 03639 jit_object_error((t_object *)x, "jit.qt.movie: loop callback executing during threaded operation."); 03640 x->restoreloop = true; 03641 return; 03642 } 03643 } 03644 #endif 03645 switch(x->loop) { 03646 case LOOP_OFF: 03647 case LOOP_SINGLEPLAYSELECTION: 03648 defer_low(x, (method)jit_qt_movie_disposecallback, NULL, 0, 0L); 03649 break; 03650 case LOOP_ON: 03651 case LOOP_PALINDROME: 03652 default: 03653 // this retriggers the soundtrack 03654 ctime = GetMovieTime(x->movie,NULL); 03655 SetMovieTimeValue(x->movie, ctime); 03656 tb = GetMovieTimeBase(x->movie); 03657 SetTimeBaseValue(tb, ctime, GetMovieTimeScale(x->movie)); 03658 break; 03659 } 03660 // get our sound looping again in SOC mode 03661 jit_qt_movie_soc_sfplay_setcues(x); 03662 03663 if (x->loopreport) { 03664 defer_low(x, (method)jit_qt_movie_looper_notify, 0L, 0, 0L); 03665 } 03666 jit_qt_movie_callback_setup(x, cb, false); 03667 } 03668 } 03669 03670 void jit_qt_movie_callback_setup(t_jit_qt_movie *x, QTCallBack cb, Boolean force) 03671 { 03672 if (SPIGOTTED) { 03673 defer_low(x, (method)jit_qt_movie_disposecallback, NULL, 0, 0L); 03674 return; 03675 } 03676 03677 if (cb) { 03678 if (force || (x->loop != LOOP_OFF && x->loop != LOOP_SINGLEPLAYSELECTION)) { 03679 long flg; 03680 03681 if (x->loop == LOOP_PALINDROME) 03682 flg = triggerAtStart | triggerAtStop; 03683 else 03684 flg = triggerAtStop; 03685 03686 CallMeWhen(cb, x->looper, (long)x, flg, 0, 0); 03687 } 03688 else { 03689 defer_low(x, (method)jit_qt_movie_disposecallback, NULL, 0, 0L); 03690 } 03691 } 03692 } 03693 03694 void jit_qt_movie_loopreport(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 03695 { 03696 if (ac && av) { 03697 x->loopreport = (jit_atom_getlong(av)) ? 1 : 0; 03698 03699 if (x->loopreport && x->movie && !x->cb) { 03700 TimeBase tb; 03701 long flg; 03702 03703 tb = GetMovieTimeBase(x->movie); 03704 x->cb = NewCallBack(tb, callBackAtExtremes); 03705 jit_qt_movie_callback_setup(x, x->cb, false); 03706 } 03707 } 03708 } 03709 03710 void jit_qt_movie_set_timebase_loop(t_jit_qt_movie *x) 03711 { 03712 TimeRecord tr; 03713 TimeBase tb; 03714 long start,end,flags,dur; 03715 long ts; 03716 PREP_M 03717 03718 if (!m) 03719 return; 03720 03721 // moved to eliminate reported crash with looppoints on G5 03722 // apparently, not good to change the timebase while a callback is active 03723 if (x->cb) { 03724 CancelCallBack(x->cb); 03725 DisposeCallBack(x->cb); 03726 x->cb = 0; 03727 } 03728 03729 tb = GetMovieTimeBase(m); 03730 flags = GetTimeBaseFlags(tb); 03731 switch(x->loop) { 03732 case LOOP_ON: flags = loopTimeBase; break; 03733 case LOOP_PALINDROME: flags = palindromeLoopTimeBase; break; 03734 case LOOP_SINGLEPLAYSELECTION: 03735 default: flags = 0; break; 03736 } 03737 03738 if (x->loop != LOOP_PALINDROME && !(SPIGOTTED)) // not a palindrome loop 03739 { 03740 Fixed rate = GetMovieRate(m); 03741 03742 if (rate && rate != FloatToFixed(x->rate)) 03743 jit_qt_movie_movierate_set(x, m, x->rate); 03744 } 03745 03746 dur = GetMovieDuration(m); 03747 ts = GetMovieTimeScale(m); 03748 03749 SetMovieSelection(m, 0, dur); 03750 SetMovieActiveSegment(m, 0, dur); 03751 start = x->looppoints[0]; 03752 end = x->looppoints[1]; 03753 03754 jit_qt_movie_inoutpoints_validate(&start, &end, 0, dur); 03755 x->looppoints[0] = start; 03756 x->looppoints[1] = end; 03757 03758 if (!dur) return; 03759 03760 GetTimeBaseTime(tb, ts, &tr); 03761 tr.value.lo = GetMovieTime(m, NULL); 03762 SetTimeBaseTime(tb, &tr); 03763 03764 // check loop duration 03765 if (end - start < (ts * 0.001)) 03766 end = start + MAX(1, ts * 0.001); 03767 03768 if (x->loop != LOOP_OFF) { 03769 SetTimeBaseFlags(tb,0); 03770 GetTimeBaseStartTime(tb, ts, &tr); 03771 tr.value.lo = start; 03772 SetTimeBaseStartTime(tb, &tr); 03773 tr.value.lo = end; 03774 SetTimeBaseStopTime(tb, &tr); 03775 SetTimeBaseFlags(tb,flags); 03776 if (x->loop == LOOP_SINGLEPLAYSELECTION) { 03777 SetMovieSelection(m, start, (end - start)); 03778 SetMovieActiveSegment(m, start, (end - start)); 03779 } 03780 } else { 03781 SetTimeBaseFlags(tb,0); 03782 GetTimeBaseStartTime(tb, ts, &tr); 03783 tr.value.lo = 0; 03784 SetTimeBaseStartTime(tb, &tr); 03785 tr.value.lo = dur; 03786 SetTimeBaseStopTime(tb, &tr); 03787 SetTimeBaseFlags(tb,flags); 03788 } 03789 03790 x->cb = NewCallBack(tb, callBackAtExtremes);//callBackAtTime); 03791 jit_qt_movie_callback_setup(x, x->cb, true); // force 03792 03793 if (SPIGOTTED) 03794 { 03795 long loop = (x->loop == LOOP_ON || x->loop == LOOP_PALINDROME); 03796 03797 if (loop) 03798 object_method(x->sfplay, ps_loopone, 3L); 03799 else 03800 object_method(x->sfplay, ps_loopone, 0L); // should turn it off 03801 03802 object_method(x->sfplay, ps_looppalin, (x->loop == LOOP_PALINDROME)); 03803 jit_qt_movie_soc_sfplay_setcues(x); 03804 } 03805 } 03806 03807 void jit_qt_movie_loopstatus(t_jit_qt_movie *x) 03808 { 03809 PREP_M 03810 03811 if (m) { 03812 long loop; 03813 Handle h; 03814 UserData ud; 03815 03816 loop = 0; 03817 h = NewHandle(1); 03818 ud = GetMovieUserData(m); 03819 if (CountUserDataType(ud, FOUR_CHAR_CODE('LOOP'))) { 03820 loop = 1; 03821 GetUserData(ud, h, FOUR_CHAR_CODE('LOOP'), 1); 03822 if (GetHandleSize(h)) 03823 if ((**(long **)h) == 1) 03824 loop = 2; 03825 } 03826 DisposeHandle(h); 03827 x->loop = loop; 03828 } 03829 } 03830 03831 void jit_qt_movie_rename(t_jit_qt_movie *x, t_symbol *s, long ac, t_atom *av) 03832 { 03833 Handle dataRef = NULL; 03834 OSType dataRefType = 0; 03835 OSErr err; 03836 short path; 03837 char name[MAX_PATH_CHARS]; 03838 03839 if (ac && av && x->movie) { 03840 GetMovieDefaultDataRef(x->movie, &dataRef, &dataRefType); 03841 if (!dataRef) { 03842 error ("jit.qt.movie: could not find diskfile"); 03843 return; 03844 } 03845 XQT_MaxPathFromDataReference(dataRef, dataRefType, &path, name, &err); 03846 path_renamefile(name, path, atom_getsym(av)->s_name); 03847 } 03848 if (dataRef) 03849 DisposeHandle(dataRef); 03850 } 03851 03852 #pragma mark - 03853 #pragma mark hints 03854 #pragma mark - 03855 03856 void jit_qt_movie_playhints(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 03857 { 03858 t_symbol *stype; 03859 long val = 0; 03860 03861 if (ac && av) { 03862 val = jit_atom_getlong(av); 03863 } 03864 stype = (t_symbol *)jit_object_method(attr, _jit_sym_getname); 03865 if (stype == gensym("highquality")) 03866 x->highquality = val; 03867 else if (stype == gensym("singlefield")) 03868 x->singlefield = val; 03869 else if (qt65 && stype == gensym("deinterlace")) 03870 x->deinterlace = val; 03871 else return; 03872 03873 jit_qt_movie_playhints_do(x); 03874 } 03875 03876 void jit_qt_movie_playhints_do(t_jit_qt_movie *x) 03877 { 03878 long mask = 0; 03879 long flag = 0; 03880 PREP_M 03881 03882 if (m) { 03883 if (x->highquality >= 0) { 03884 mask = hintsHighQuality; 03885 flag = (x->highquality) ? mask : 0; 03886 jit_qt_movie_playhints_assign(m, mask, flag); 03887 } 03888 03889 if (x->singlefield >= 0) { 03890 mask = hintsSingleField; 03891 flag = (x->singlefield) ? mask : 0; 03892 jit_qt_movie_playhints_assign(m, mask, flag); 03893 } 03894 03895 if (x->deinterlace >= 0) { 03896 mask = 1L << 26; //hintsDeinterlaceFields; 03897 flag = (x->deinterlace) ? mask : 0; 03898 jit_qt_movie_playhints_assign(m, mask, flag); 03899 } 03900 } 03901 } 03902 03903 void jit_qt_movie_playhints_assign(Movie m, long mask, long flag) 03904 { 03905 long i = 1; 03906 03907 SetMoviePlayHints(m, flag, mask); 03908 03909 while (1) { 03910 Track track; 03911 long preloadtime, preloaddur, preloadflag; 03912 long hint = 0; 03913 03914 if (track = GetMovieIndTrackType(m, i++, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)) { 03915 GetTrackLoadSettings(track, &preloadtime, &preloaddur, &preloadflag, &hint); 03916 if (flag) { 03917 hint |= mask; 03918 } 03919 else { 03920 hint &= ~(mask); 03921 } 03922 SetTrackLoadSettings(track, 0, 0, 0, hint); 03923 } 03924 else break; 03925 } 03926 } 03927 t_jit_err jit_qt_movie_getplayhints(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 03928 { 03929 long mask = 0; 03930 long flag = 0; 03931 t_symbol *stype, *sname = _jit_sym_nothing; 03932 03933 if ((*ac)&&(*av)) { 03934 //memory passed in, use it 03935 } else { 03936 //otherwise allocate memory 03937 *ac = 1; 03938 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 03939 *ac = 0; 03940 return JIT_ERR_OUT_OF_MEM; 03941 } 03942 } 03943 03944 stype = (t_symbol *)jit_object_method(attr, _jit_sym_getname); 03945 if (x->movie) { 03946 Track track; 03947 Media media; 03948 03949 if (stype == gensym("highquality")) 03950 mask = hintsHighQuality; 03951 else if (stype == gensym("singlefield")) 03952 mask = hintsSingleField; 03953 else if (qt65 && stype == gensym("deinterlace")) 03954 mask = 1L << 26; //hintsDeinterlaceFields; 03955 else goto out; 03956 03957 // currently only checks the first video track. this can change. 03958 if (track = GetMovieIndTrackType(x->movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)) { 03959 if (media = GetTrackMedia(track)) { 03960 GetMediaPlayHints(media, &flag); 03961 } 03962 } 03963 } else { 03964 if (stype == gensym("highquality")) 03965 mask = flag = x->highquality; 03966 else if (stype == gensym("singlefield")) 03967 mask = flag = x->singlefield; 03968 else if (qt65 && stype == gensym("deinterlace")) 03969 mask = flag = x->deinterlace; 03970 else goto out; 03971 } 03972 out: 03973 jit_atom_setlong(*av, (mask & flag) ? 1 : 0); 03974 return JIT_ERR_NONE; 03975 } 03976 03977 t_jit_err jit_qt_movie_timecode_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 03978 { 03979 if (x->movie) { 03980 Track track; 03981 Media media; 03982 TimeCodeDef tcd; 03983 TimeCodeRecord tcr; 03984 03985 if (track = GetMovieIndTrackType(x->movie, 1, TimeCodeMediaType, movieTrackMediaType)) { 03986 if (media = GetTrackMedia(track)) { 03987 if (noErr == TCGetCurrentTimeCode(GetMediaHandler(media), NULL, &tcd, &tcr, NULL)) { 03988 if ((*ac)&&(*av)) { 03989 //memory passed in, use it 03990 } else { 03991 //otherwise allocate memory 03992 if (tcd.flags & tcCounter) 03993 *ac = 1; 03994 else 03995 *ac = 4; 03996 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 03997 *ac = 0; 03998 return JIT_ERR_OUT_OF_MEM; 03999 } 04000 if (tcd.flags & tcCounter) { 04001 jit_atom_setlong(*av, tcr.c.counter); 04002 } 04003 else { 04004 if ((tcd.flags & tcNegTimesOK) && (tcr.t.minutes & tctNegFlag)) 04005 jit_atom_setlong(*av, -(tcr.t.hours)); 04006 else 04007 jit_atom_setlong(*av, tcr.t.hours); 04008 jit_atom_setlong(*av + 1, tcr.t.minutes); 04009 jit_atom_setlong(*av + 2, tcr.t.seconds); 04010 jit_atom_setlong(*av + 3, tcr.t.frames); 04011 } 04012 } 04013 } 04014 } 04015 } 04016 } 04017 return JIT_ERR_NONE; 04018 } 04019 04020 t_jit_err jit_qt_movie_timecodeinfo_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04021 { 04022 if (x->movie) { 04023 Track track; 04024 Media media; 04025 TimeCodeDef tcd; 04026 04027 if (track = GetMovieIndTrackType(x->movie, 1, TimeCodeMediaType, movieTrackMediaType)) { 04028 if (media = GetTrackMedia(track)) { 04029 if (noErr == TCGetCurrentTimeCode(GetMediaHandler(media), NULL, &tcd, NULL, NULL)) { 04030 if ((*ac)&&(*av)) { 04031 //memory passed in, use it 04032 } else { 04033 //otherwise allocate memory 04034 *ac = 4; 04035 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04036 *ac = 0; 04037 return JIT_ERR_OUT_OF_MEM; 04038 } 04039 if (tcd.flags & tcDropFrame) 04040 jit_atom_setsym(*av, gensym("drop")); 04041 else 04042 jit_atom_setsym(*av, gensym("nondrop")); 04043 04044 if (tcd.flags & tcCounter) 04045 jit_atom_setsym(*av + 1, gensym("counter")); 04046 else 04047 jit_atom_setsym(*av + 1, gensym("timer")); 04048 jit_atom_setfloat(*av + 2, (float)((double)tcd.fTimeScale / (double)tcd.frameDuration)); 04049 jit_atom_setlong(*av + 3, tcd.numFrames); // "frames per second" 04050 } 04051 } 04052 } 04053 } 04054 } 04055 return JIT_ERR_NONE; 04056 } 04057 04058 // not used 04059 t_jit_err jit_qt_movie_timecodevis_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04060 { 04061 if (x->movie) { 04062 Track track; 04063 Media media; 04064 long flags; 04065 04066 if (track = GetMovieIndTrackType(x->movie, 1, TimeCodeMediaType, movieTrackMediaType)) { 04067 if (media = GetTrackMedia(track)) { 04068 if (noErr == TCGetTimeCodeFlags(GetMediaHandler(media), &flags)) { 04069 if ((*ac)&&(*av)) { 04070 //memory passed in, use it 04071 } else { 04072 //otherwise allocate memory 04073 *ac = 1; 04074 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04075 *ac = 0; 04076 return JIT_ERR_OUT_OF_MEM; 04077 } 04078 } 04079 jit_atom_setlong(*av, (flags & tcdfShowTimeCode) ? 1 : 0); 04080 } 04081 } 04082 } 04083 } 04084 return JIT_ERR_NONE; 04085 } 04086 04087 void jit_qt_movie_timecodevis(t_jit_qt_movie *x) 04088 { 04089 PREP_M 04090 04091 if (m) { 04092 Track track; 04093 Media media; 04094 04095 if (track = GetMovieIndTrackType(m, 1, TimeCodeMediaType, movieTrackMediaType)) { 04096 if (media = GetTrackMedia(track)) { 04097 TCSetTimeCodeFlags(GetMediaHandler(media), (long)x->timecodevis, tcdfShowTimeCode); 04098 } 04099 } 04100 } 04101 } 04102 04103 t_jit_err jit_qt_movie_timecodevis_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04104 { 04105 long tc; 04106 04107 if (ac && av) { 04108 tc = jit_atom_getlong(av); 04109 x->timecodevis = (tc) ? 1 : 0; 04110 jit_qt_movie_timecodevis(x); 04111 } 04112 return JIT_ERR_NONE; 04113 } 04114 04115 #ifdef NOTYET 04116 t_jit_err jit_qt_movie_brightness_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04117 { 04118 if (x->movie) { 04119 Float32 brightness = 0.; 04120 04121 if ((*ac)&&(*av)) { 04122 //memory passed in, use it 04123 } else { 04124 //otherwise allocate memory 04125 *ac = 1; 04126 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04127 *ac = 0; 04128 return JIT_ERR_OUT_OF_MEM; 04129 } 04130 } 04131 mGetMovieVisualBrightness(x->movie, &brightness, 0L); 04132 jit_atom_setfloat(*av, brightness); 04133 } 04134 return JIT_ERR_NONE; 04135 } 04136 04137 t_jit_err jit_qt_movie_brightness_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04138 { 04139 Float32 brightness; 04140 OSErr err; 04141 04142 if (ac && av) { 04143 brightness = jit_atom_getfloat(av); 04144 err = mSetMovieVisualBrightness(x->movie, brightness, 0L); 04145 } 04146 return JIT_ERR_NONE; 04147 } 04148 #endif 04149 04150 #pragma mark - 04151 #pragma mark attributes 04152 #pragma mark - 04153 04154 void jit_qt_movie_autosave(t_jit_qt_movie *x) 04155 { 04156 if (x->movie && x->autosave) 04157 jit_object_method(x, ps_savemovie); 04158 } 04159 04160 long jit_qt_movie_rate_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04161 { 04162 float oldrate = x->rate; 04163 Boolean here = true, anywhere; 04164 04165 x->rate = jit_atom_getfloat(av); 04166 if (x->movie) { 04167 if (x->rate && oldrate) { 04168 if (jit_qt_movie_threadstate_get(x, THREADSTATE_UNSAFE)) 04169 jit_qt_movie_proxy_method(x, ps_start, 0, NULL); 04170 else 04171 jit_qt_movie_movierate_set(x, x->movie, x->rate); // faster 04172 } 04173 else if (!oldrate && x->rate) 04174 jit_qt_movie_proxy_method(x, ps_start, 0, NULL); 04175 else 04176 jit_qt_movie_proxy_method(x, (x->preroll) ? ps_asyncstop : ps_stop, 0, NULL); // trigger stop in the case of 0, so that we preload if possible 04177 return JIT_ERR_NONE; 04178 } else { 04179 return JIT_ERR_GENERIC; 04180 } 04181 } 04182 04183 long jit_qt_movie_getmovierate(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04184 { 04185 if ((*ac)&&(*av)) { 04186 //memory passed in, use it 04187 } else { 04188 //otherwise allocate memory 04189 *ac = 1; 04190 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04191 *ac = 0; 04192 return JIT_ERR_OUT_OF_MEM; 04193 } 04194 } 04195 if (!x->movie) 04196 jit_atom_setfloat(*av, 0); 04197 else { 04198 jit_atom_setfloat(*av, FixedToFloat(GetMovieRate(x->movie))); 04199 } 04200 04201 return JIT_ERR_NONE; 04202 } 04203 04204 long jit_qt_movie_vol_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04205 { 04206 x->vol = jit_atom_getfloat(av); 04207 CLIP(x->vol,-1.,1.); 04208 if (x->movie) { 04209 SetMovieVolume(x->movie,x->vol*255.); 04210 return JIT_ERR_NONE; 04211 } else { 04212 return JIT_ERR_GENERIC; 04213 } 04214 } 04215 04216 long jit_qt_movie_time_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04217 { 04218 if (ac && av && x->movie) { 04219 long time = jit_atom_getlong(av); 04220 TimeBase tb; 04221 TimeRecord tr; 04222 04223 if (x->loop == LOOP_SINGLEPLAYSELECTION) 04224 CLIP(time, x->looppoints[0], x->looppoints[1]); 04225 04226 tb = GetMovieTimeBase(x->movie); 04227 GetTimeBaseStartTime(tb, GetMovieTimeScale(x->movie), &tr); // fill out struct 04228 04229 tr.value.lo = 0; 04230 SetTimeBaseStartTime(tb, &tr); 04231 tr.value.lo = GetMovieDuration(x->movie); 04232 SetTimeBaseStopTime(tb, &tr); 04233 04234 jit_qt_movie_setmovietimevalue(x, x->movie, time); 04235 // SetMovieTimeValue(x->movie, time); //time is int 04236 x->restoreloop = true; 04237 } 04238 return JIT_ERR_NONE; 04239 } 04240 04241 long jit_qt_movie_time_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04242 { 04243 if ((*ac)&&(*av)) { 04244 //memory passed in, use it 04245 } else { 04246 //otherwise allocate memory 04247 *ac = 1; 04248 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04249 *ac = 0; 04250 return JIT_ERR_OUT_OF_MEM; 04251 } 04252 } 04253 jit_atom_setlong(*av,0); 04254 if (x->movie) { 04255 if (SPIGOTTED && x->sfplay_clock_enabled) { 04256 // get current position 04257 double pos, poserr, realpos; 04258 TimeScale timescale; 04259 04260 jit_qt_movie_soc_timingvectors_get(x, &pos, &poserr); 04261 realpos = (pos + poserr) / 1000.; 04262 timescale = GetMovieTimeScale(x->movie); 04263 04264 (*av)->a_w.w_long = (TimeValue)(realpos * timescale); 04265 } else { 04266 (*av)->a_w.w_long = GetMovieTime(x->movie,NULL); 04267 } 04268 } 04269 return JIT_ERR_NONE; 04270 } 04271 04272 long jit_qt_movie_edittime_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04273 { 04274 if ((*ac)&&(*av)) { 04275 //memory passed in, use it 04276 } else { 04277 //otherwise allocate memory 04278 *ac = 1; 04279 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04280 *ac = 0; 04281 return JIT_ERR_OUT_OF_MEM; 04282 } 04283 } 04284 jit_atom_setlong(*av,0); 04285 if (x->movie) { 04286 long time; 04287 04288 if (SPIGOTTED && x->sfplay_clock_enabled) { 04289 // get current position 04290 double pos, poserr, realpos; 04291 TimeScale timescale; 04292 04293 jit_qt_movie_soc_timingvectors_get(x, &pos, &poserr); 04294 realpos = (pos + poserr) / 1000.; 04295 timescale = GetMovieTimeScale(x->movie); 04296 04297 time = (TimeValue)(realpos * timescale); 04298 } else { 04299 time = GetMovieTime(x->movie,NULL); 04300 } 04301 jit_qt_movie_timevalues_convertback(x, x->movie, &time, NULL, NULL, NULL, NULL); 04302 jit_atom_setlong(*av, time); 04303 } 04304 04305 return JIT_ERR_NONE; 04306 } 04307 04308 void jit_qt_movie_edittime_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04309 { 04310 if (ac && av && x->movie) { 04311 long time = jit_atom_getlong(av); 04312 04313 jit_qt_movie_timevalues_convert(x, x->movie, &time, NULL, NULL, NULL, NULL); 04314 jit_qt_movie_setmovietimevalue(x, x->movie, time); 04315 } 04316 } 04317 04318 long jit_qt_movie_timescale_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04319 { 04320 TimeRecord tr; 04321 long timescale = 0; 04322 04323 if ((*ac)&&(*av)) { 04324 //memory passed in, use it 04325 } else { 04326 //otherwise allocate memory 04327 *ac = 1; 04328 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04329 *ac = 0; 04330 return JIT_ERR_OUT_OF_MEM; 04331 } 04332 } 04333 if (x->movie) { 04334 GetMovieTime(x->movie,&tr); 04335 timescale = tr.scale; 04336 } 04337 jit_atom_setlong(*av,timescale); 04338 return JIT_ERR_NONE; 04339 } 04340 04341 long jit_qt_movie_poster_set(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04342 { 04343 long time; 04344 04345 if (x->movie) { 04346 if (ac && av) 04347 time = jit_atom_getlong(av); 04348 else 04349 time = GetMovieTime(x->movie, NULL); 04350 04351 SetMoviePosterTime(x->movie, time); 04352 } 04353 return JIT_ERR_NONE; 04354 } 04355 04356 long jit_qt_movie_poster_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04357 { 04358 long time = 0; 04359 04360 if ((*ac)&&(*av)) { 04361 //memory passed in, use it 04362 } else { 04363 //otherwise allocate memory 04364 *ac = 1; 04365 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04366 *ac = 0; 04367 return JIT_ERR_OUT_OF_MEM; 04368 } 04369 } 04370 if (x->movie) { 04371 time = GetMoviePosterTime(x->movie); 04372 } 04373 jit_atom_setlong(*av,time); 04374 return JIT_ERR_NONE; 04375 } 04376 04377 long jit_qt_movie_framecount_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04378 { 04379 long time = 0; 04380 04381 if ((*ac)&&(*av)) { 04382 //memory passed in, use it 04383 } else { 04384 //otherwise allocate memory 04385 *ac = 1; 04386 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04387 *ac = 0; 04388 return JIT_ERR_OUT_OF_MEM; 04389 } 04390 } 04391 if (x->movie) { 04392 time = QT_GetFramecount(x->movie); 04393 } 04394 jit_atom_setlong(*av,time); 04395 return JIT_ERR_NONE; 04396 } 04397 04398 double jit_qt_movie_moviefps_get(Movie m) 04399 { 04400 double fps = 0; 04401 OSErr err = noErr; 04402 04403 if (m) { 04404 MediaHandler mh = NULL; 04405 Track track = NULL; 04406 Media media = NULL; 04407 Boolean isMpeg = false; 04408 04409 if (track = GetMovieIndTrackType(m, 1, kCharacteristicHasVideoFrameRate, movieTrackCharacteristic)) { 04410 if (media = GetTrackMedia(track)) { 04411 if (mh = GetMediaHandler(media)) { 04412 err = MediaHasCharacteristic(mh, kCharacteristicIsAnMpegTrack, &isMpeg); 04413 } 04414 } 04415 } 04416 04417 if ((err == noErr) && isMpeg) { 04418 MHInfoEncodedFrameRateRecord encodedFrameRate; 04419 Size encodedFrameRateSize = sizeof(encodedFrameRate); 04420 04421 /* due to a bug in QuickTime, we must task the movie 04422 first before obtaining our frame rate value */ 04423 MoviesTask(m, 0); 04424 04425 if (!(err = MediaGetPublicInfo(mh, kMHInfoEncodedFrameRate, &encodedFrameRate, &encodedFrameRateSize))) { 04426 fps = FixedToDouble(encodedFrameRate.encodedFrameRate); 04427 } 04428 } 04429 else /* were dealing with non-MPEG media, so use the "old" method */ 04430 { 04431 long sampleCount = 0; 04432 04433 sampleCount = GetMediaSampleCount(media); 04434 if (!(err = GetMoviesError()) && sampleCount) { 04435 TimeValue64 duration; 04436 TimeValue64 timeScale; 04437 04438 if (qt7) 04439 duration = mGetMediaDisplayDuration(media); 04440 else 04441 duration = GetMediaDuration(media); 04442 if (!(err = GetMoviesError())) { 04443 timeScale = GetMediaTimeScale(media); 04444 if (!(err = GetMoviesError())) 04445 fps = sampleCount*(double)timeScale/(double)duration; 04446 } 04447 } 04448 } 04449 } 04450 04451 return fps; 04452 } 04453 04454 long jit_qt_movie_fps_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04455 { 04456 double fps = x->fps; 04457 04458 /* initialize frame rate value */ 04459 if ((*ac)&&(*av)) { 04460 //memory passed in, use it 04461 } else { 04462 //otherwise allocate memory 04463 *ac = 1; 04464 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04465 *ac = 0; 04466 return JIT_ERR_OUT_OF_MEM; 04467 } 04468 } 04469 04470 if (!fps) { 04471 fps = jit_qt_movie_moviefps_get(x->movie); 04472 x->fps = fps; 04473 } 04474 04475 jit_atom_setfloat(*av, fps); 04476 return JIT_ERR_NONE; 04477 } 04478 04479 void jit_qt_movie_window_attach(t_jit_qt_movie *x, t_symbol *name); 04480 void jit_qt_movie_window_attach(t_jit_qt_movie *x, t_symbol *name) 04481 { 04482 jit_object_attach(name, x); 04483 x->window = name; 04484 } 04485 04486 void jit_qt_movie_window_detach(t_jit_qt_movie *x); 04487 void jit_qt_movie_window_detach(t_jit_qt_movie *x) 04488 { 04489 t_object *jw; 04490 04491 jit_object_detach(x->window,x); 04492 #ifdef WIN_VERSION 04493 // destroy port assoc 04494 if ((jw=jit_object_findregistered(x->window)) && 04495 (jit_object_method(jw, ps_class_jit_window))) 04496 { 04497 void *mw = NULL; 04498 04499 jit_object_method(jw, ps_get_window_ptr, &mw); 04500 if (mw) { 04501 DestroyPortAssociation((CGrafPtr)GetNativeWindowPort(mw)); 04502 } 04503 } 04504 #endif 04505 x->window = _jit_sym_nothing; 04506 } 04507 04508 void jit_qt_movie_window(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04509 { 04510 // static long tries = 0; 04511 t_symbol *wname; 04512 void *jw; 04513 04514 wname = jit_atom_getsym(av); 04515 04516 if (wname!=_jit_sym_nothing) 04517 { 04518 if ((jw=jit_object_findregistered(wname))&& 04519 (jit_object_method(jw,ps_class_jit_window))) 04520 { 04521 jit_qt_movie_window_detach(x); 04522 jit_qt_movie_window_attach(x, wname); 04523 } else { 04524 jit_object_error((t_object *)x, "jit.qt.movie: could not attach to window %s",wname->s_name); 04525 jit_qt_movie_window_detach(x); 04526 /* 04527 // could not find registered window; try again later 04528 if (tries < 3) { 04529 tries++; 04530 defer_low(x, (method)object_attr_setvalueof, gensym("window"), 1, av); 04531 return; 04532 } 04533 */ 04534 } 04535 } else { 04536 jit_qt_movie_window_detach(x); 04537 jit_qt_movie_mreset(x); 04538 } 04539 jit_qt_movie_movie_prep(x); 04540 // tries = 0; 04541 } 04542 04543 04544 t_jit_err jit_qt_movie_colormode(t_jit_qt_movie *x, void *attr, long argc, t_atom *argv) 04545 { 04546 t_symbol *s = jit_atom_getsym(argv); 04547 04548 x->cmode_changed = CMODE_UNCHANGED; 04549 if (x->colormode != s) { 04550 if (x->colormode == ps_argb) { 04551 if (s == ps_uyvy) { 04552 x->cmode_changed = CMODE_ARGB2UYVY; 04553 x->colormode = ps_uyvy; 04554 x->pixelformat = k2vuyPixelFormat; 04555 } 04556 } 04557 else if (x->colormode == ps_uyvy) { 04558 if (s == ps_argb) { 04559 x->cmode_changed = CMODE_UYVY2ARGB; 04560 x->colormode = ps_argb; 04561 x->pixelformat = k32ARGBPixelFormat; 04562 } 04563 } 04564 } 04565 if (x->cmode_changed) 04566 x->clearflag = true; 04567 04568 // matrix will be resized, etc. in matrix_calc 04569 return JIT_ERR_NONE; 04570 } 04571 04572 04573 t_jit_err jit_qt_movie_moviedim_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04574 { 04575 if ((*ac)&&(*av)) { 04576 //memory passed in, use it 04577 } else { 04578 //otherwise allocate memory 04579 *ac = 2; 04580 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04581 *ac = 0; 04582 return JIT_ERR_OUT_OF_MEM; 04583 } 04584 } 04585 if (x->movie) { 04586 jit_atom_setlong(*av, x->movie_rect.right); 04587 jit_atom_setlong(*av + 1, x->movie_rect.bottom); 04588 } 04589 else { 04590 jit_atom_setlong(*av, 0); 04591 jit_atom_setlong(*av + 1, 0); 04592 } 04593 return JIT_ERR_NONE; 04594 } 04595 04596 t_jit_err jit_qt_movie_moviename_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04597 { 04598 if ((*ac)&&(*av)) { 04599 //memory passed in, use it 04600 } else { 04601 //otherwise allocate memory 04602 *ac = 1; 04603 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04604 *ac = 0; 04605 return JIT_ERR_OUT_OF_MEM; 04606 } 04607 } 04608 if (x->movie) { 04609 Handle dataRef = NULL; 04610 OSType dataRefType = 0; 04611 char cname[MAX_PATH_CHARS] = "<none>"; 04612 CFStringRef str = NULL; 04613 OSErr err; 04614 04615 GetMovieDefaultDataRef(x->movie, &dataRef, &dataRefType); 04616 if (dataRef) { 04617 if (dataRefType == rAliasType) { 04618 QTGetDataReferenceTargetNameCFString(dataRef, dataRefType, &str); 04619 if (str) { 04620 CFStringGetCString(str, cname, MAX_PATH_CHARS, kCFStringEncodingUTF8); 04621 CFRelease(str); 04622 } 04623 } 04624 DisposeHandle(dataRef); 04625 } 04626 else 04627 jit_object_error((t_object *)x, "jit.qt.movie: movie is not a disk file"); 04628 jit_atom_setsym(*av,gensym(cname)); 04629 } else { 04630 jit_atom_setsym(*av, _jit_sym_nothing); 04631 } 04632 return JIT_ERR_NONE; 04633 } 04634 04635 t_jit_err jit_qt_movie_moviepath_get(t_jit_qt_movie *x, void *attr, long *ac, t_atom **av) 04636 { 04637 if ((*ac)&&(*av)) { 04638 //memory passed in, use it 04639 } else { 04640 //otherwise allocate memory 04641 *ac = 1; 04642 if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { 04643 *ac = 0; 04644 return JIT_ERR_OUT_OF_MEM; 04645 } 04646 } 04647 if (x->movie) { 04648 Handle dataRef = NULL; 04649 OSType dataRefType = 0; 04650 char cname[MAX_PATH_CHARS] = "<none>"; 04651 CFStringRef str = NULL; 04652 OSErr err; 04653 04654 GetMovieDefaultDataRef(x->movie, &dataRef, &dataRefType); 04655 if (dataRef) { 04656 if (dataRefType == rAliasType) { 04657 QTGetDataReferenceFullPathCFString(dataRef, dataRefType, kQTNativeDefaultPathStyle, &str); 04658 if (str) { 04659 CFStringGetCString(str, cname, MAX_PATH_CHARS, kCFStringEncodingUTF8); 04660 CFRelease(str); 04661 } 04662 } 04663 DisposeHandle(dataRef); 04664 } 04665 else 04666 jit_object_error((t_object *)x, "jit.qt.movie: movie is not a disk file"); 04667 jit_atom_setsym(*av,gensym(cname)); 04668 } else { 04669 jit_atom_setsym(*av, _jit_sym_nothing); 04670 } 04671 return JIT_ERR_NONE; 04672 } 04673 04674 // what if we make a clone of the movie, and do this search from here, and then set the frame 04675 long QTStep_DrawVideoSampleNextOrPrev(t_jit_qt_movie *x, Movie theMovie, long jump) 04676 { 04677 TimeValue myCurrTime; 04678 TimeValue myNextTime; 04679 short myFlags; 04680 OSType myTypes[1]; 04681 long myErr = noErr; 04682 Fixed theRate; 04683 long i; 04684 04685 if (theMovie == NULL) 04686 return 0; 04687 04688 if (jump == 0) 04689 return 0; 04690 04691 myFlags = nextTimeStep; // we want the next frame in the movie's media 04692 myTypes[0] = VisualMediaCharacteristic; // we want video samples 04693 myCurrTime = GetMovieTime(theMovie, NULL); 04694 04695 if (jump >= 0) 04696 theRate = fixed1; 04697 else 04698 theRate = fixed1neg; 04699 04700 jump = ABS(jump); 04701 04702 for (i = 0; i < jump; i++) { 04703 GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, myCurrTime, theRate, &myNextTime, NULL); 04704 if (GetMoviesError() != noErr) 04705 return 0; 04706 if (myNextTime == -1 && i == (jump - 1)) { 04707 if (theRate == fixed1) 04708 myNextTime = GetMovieDuration(theMovie) - 1; 04709 else 04710 myNextTime = 0; 04711 } 04712 myCurrTime = myNextTime; 04713 } 04714 return myNextTime; 04715 } 04716 04717 long QT_GetFramecount (Movie theMovie) 04718 { 04719 TimeValue myCurrTime; 04720 TimeValue myNextTime; 04721 short myFlags; 04722 OSType myTypes[1]; 04723 long myErr = noErr; 04724 Fixed theRate; 04725 long count=0; 04726 04727 if (theMovie == NULL) 04728 return 0; 04729 04730 myFlags = nextTimeStep; // we want the next frame in the movie's media 04731 myTypes[0] = VisualMediaCharacteristic; // we want video samples 04732 myCurrTime = 0; 04733 04734 theRate = fixed1; 04735 04736 while (myErr==noErr) { 04737 GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, myCurrTime, theRate, &myNextTime, NULL); 04738 myErr = GetMoviesError(); 04739 myCurrTime = myNextTime; 04740 if (myErr==noErr) 04741 count++; 04742 } 04743 04744 return count; 04745 } 04746 04747 #pragma mark - 04748 #pragma mark event 04749 #pragma mark - 04750 04751 /* 04752 long jit_qt_movie_progress(Movie movie, short message, short operation, Fixed percent, long s) 04753 { 04754 jit_object_post((t_object *)x,"progress: %d %d %d", message, operation, percent); 04755 switch(message) { 04756 case movieProgressOpen: 04757 case movieProgressClose: 04758 break; 04759 case movieProgressUpdatePercent: 04760 switch(operation) { 04761 case progressOpFlatten: 04762 case progressOpInsertTrackSegment: 04763 case progressOpInsertMovieSegment: 04764 case progressOpPaste: 04765 case progressOpAddMovieSelection: 04766 case progressOpCopy: 04767 case progressOpCut: 04768 break; 04769 case progressOpLoadMovieIntoRam: 04770 case progressOpLoadTrackIntoRam: 04771 case progressOpLoadMediaIntoRam: 04772 jit_object_post((t_object *)x,"ramload: %f complete", (FixedToFloat(percent))); 04773 break; 04774 case progressOpImportMovie: 04775 jit_object_post((t_object *)x,"import: %f complete", (FixedToFloat(percent))); 04776 break; 04777 case progressOpExportMovie: 04778 jit_object_post((t_object *)x,"export: %f complete", (FixedToFloat(percent))); 04779 break; 04780 } 04781 break; 04782 } 04783 return 0; 04784 } 04785 */ 04786 t_jit_err jit_qt_movie_unique(t_jit_qt_movie *x, void *attr, long ac, t_atom *av) 04787 { 04788 if (ac && av) { 04789 x->unique = (jit_atom_getlong(av)) ? true : false; 04790 jit_qt_movie_unique_nexttime_get(x, -1); 04791 } 04792 return JIT_ERR_NONE; 04793 } 04794 04795 Boolean jit_qt_movie_unique_nexttime_get(t_jit_qt_movie *x, TimeValue time) 04796 { 04797 if (x->movie && time >= 0) { 04798 OSType types[1]; 04799 TimeValue prev; 04800 TimeValue dur; 04801 04802 types[0] = VisualMediaCharacteristic; 04803 GetMovieNextInterestingTime(x->movie, nextTimeStep /*| nextTimeEdgeOK*/ /*nextTimeMediaSample | nextTimeEdgeOK*/, 1, types, time, fixed1, &x->unique_nexttime, NULL); 04804 if (x->unique_nexttime == -1 && time > 0) {// handle the far edge 04805 GetMovieNextInterestingTime(x->movie, nextTimeMediaSample | nextTimeEdgeOK, 1, types, time, fixed1, &x->unique_nexttime, NULL); 04806 if (x->unique_nexttime == x->unique_lasttime) 04807 return false; 04808 } 04809 if (x->unique_nexttime == -1 && x->unique_lasttime != 0x80000000) { 04810 x->unique_prevtime = x->unique_lasttime; 04811 x->unique_nexttime = x->unique_lasttime; 04812 return false; 04813 } 04814 GetMovieNextInterestingTime(x->movie, nextTimeStep | nextTimeEdgeOK /*nextTimeMediaSample | nextTimeEdgeOK*/, 1, types, time, fixed1neg, &x->unique_prevtime, NULL); 04815 if (x->unique_prevtime == -1 || x->unique_nexttime == -1) { 04816 long lasttime = x->unique_lasttime; 04817 04818 if (time > x->unique_prevtime && time != x->unique_lasttime) { 04819 x->unique_lasttime = time; 04820 jit_qt_movie_task(x); 04821 } 04822 04823 x->unique_nexttime = 0x80000000; 04824 x->unique_prevtime = 0x7FFFFFFF; 04825 04826 // jit_object_post((t_object *)x,"next %d prev %d", x->unique_nexttime, x->unique_prevtime); 04827 if (lasttime == 0x80000000) { // force first frame 04828 x->unique_lasttime = time; 04829 return true; 04830 } else 04831 return false; 04832 } 04833 // jit_object_post((t_object *)x,"next %d prev %d", x->unique_nexttime, x->unique_prevtime); 04834 } 04835 else { 04836 x->unique_nexttime = 0x80000000; 04837 x->unique_prevtime = 0x7FFFFFFF; 04838 // jit_object_post((t_object *)x,"next %d prev %d", x->unique_nexttime, x->unique_prevtime); 04839 } 04840 x->unique_nexttime--; 04841 x->unique_lasttime = time; 04842 return true; 04843 } 04844 04845 Boolean jit_qt_movie_unique_getready(t_jit_qt_movie *x) 04846 { 04847 if (x->unique && !jit_qt_movie_isflash(x->movie)) { 04848 TimeValue time; 04849 04850 time = GetMovieTime(x->movie, NULL); 04851 if (time > x->unique_nexttime || time < x->unique_prevtime) { 04852 #ifdef DROPREPORT // doesn't really work yet 04853 if (x->dropreport) { 04854 TimeValue from; 04855 TimeValue to; 04856 OSType types[1]; 04857 long count = 0; 04858 TimeValue newtime; 04859 04860 if (time > x->unique_nexttime) { 04861 from = x->unique_nexttime; 04862 to = time; 04863 } 04864 else { 04865 from = time; 04866 to = x->unique_prevtime; 04867 } 04868 types[0] = VisualMediaCharacteristic; 04869 newtime = from; 04870 do { 04871 GetMovieNextInterestingTime(x->movie, nextTimeMediaSample, 1, types, from, fixed1, &newtime, NULL); 04872 ++count; 04873 from = newtime; 04874 if (newtime == -1) { 04875 count = 0; 04876 break; 04877 } 04878 } while (newtime < to); 04879 if (count > 1) // doesn't work anyway, but should be converted to an atombuf when it does 04880 jit_object_notify(x, ps_dropped, (void *)(count - 1)); 04881 } 04882 #endif 04883 return jit_qt_movie_unique_nexttime_get(x, time); 04884 } 04885 return false; 04886 } 04887 else return true; 04888 } 04889 04890 void jit_qt_movie_clear(t_jit_qt_movie *x) 04891 { 04892 x->clearflag = true; 04893 } 04894 04895 void jit_qt_movie_do_clear_offscreen(GWorldPtr gw, t_symbol *colormode) 04896 { 04897 if (colormode == ps_uyvy) 04898 jit_gworld_clear(gw, 0x80108010); // uyvy zero = 128, 16, 128, 16 04899 else 04900 jit_gworld_clear(gw, 0xFF000000); 04901 } 04902 04903 t_jit_err jit_qt_movie_clear_offscreen(t_jit_qt_movie *x) 04904 { 04905 if (x->offscreen) { 04906 jit_qt_movie_do_clear_offscreen(x->offscreen, x->colormode); 04907 } 04908 x->clearflag = false; 04909 return JIT_ERR_NONE; 04910 } 04911 04912 void jit_qt_movie_dispose_gworld(t_jit_qt_movie *x) 04913 { 04914 t_jit_matrix_info info; 04915 void *mxptr; 04916 04917 if (x->movie) 04918 SetMovieGWorld(x->movie, NULL, NULL); 04919 04920 if (x->offscreen) { 04921 DisposeGWorld(x->offscreen); 04922 x->offscreen = NULL; 04923 } 04924 } 04925 04926 // should not call this directly -- call jit_qt_movie_mreset instead 04927 OSErr jit_qt_movie_rebuild_gworld(t_jit_qt_movie *x) 04928 { 04929 OSErr err; 04930 04931 // if (x->mwrapped == MWRAP_WRAPPED) 04932 // jit_object_post((t_object *)x,"unwrapping matrix"); 04933 x->mwrapped = MWRAP_UNWRAPPED; 04934 04935 jit_qt_movie_dispose_gworld(x); 04936 04937 if (err = QTNewGWorld(&x->offscreen, x->pixelformat, &x->movie_rect, NULL, NULL, 0)) { 04938 jit_object_error((t_object *)x, "jit.qt.movie: could not create new gworld"); 04939 return err; 04940 } 04941 04942 jit_qt_movie_clear_offscreen(x); 04943 04944 if (x->movie) { 04945 SetMovieGWorld(x->movie, x->offscreen, NULL); 04946 if (x->moviecontroller) 04947 MCMovieChanged(x->moviecontroller, x->movie); 04948 } 04949 return noErr; 04950 } 04951 04952 OSErr jit_qt_movie_mreset(t_jit_qt_movie *x) 04953 { 04954 PixMapHandle pmh; 04955 t_jit_matrix_info info; 04956 OSErr err = noErr; 04957 GWorldPtr gw = NULL; 04958 Rect r; 04959 04960 // x->mwrapped = MWRAP_TRYAGAIN; 04961 if (x->window != _jit_sym_nothing || x->temp_window != _jit_sym_nothing) 04962 return err; 04963 04964 if (!x->loadingmovie) { 04965 if (err = jit_qt_movie_rebuild_gworld(x)) 04966 return err; 04967 } 04968 gw = x->offscreen; 04969 if (gw) { 04970 // wrap offscreen in matrix 04971 pmh = GetGWorldPixMap(gw); 04972 if (pmh) { 04973 r = x->movie_rect; // ideally, but not currently possible: GetPixBounds(pmh, &r); 04974 04975 04976 jit_object_method(x->wrapmatrix, _jit_sym_getinfo, &info); 04977 info.type = _jit_sym_char; 04978 info.planecount = 4; 04979 info.dimcount = 2; 04980 if (x->colormode == ps_uyvy) 04981 info.dim[0] = (r.right - r.left) / 2; 04982 else 04983 info.dim[0] = (r.right - r.left); 04984 info.dim[1] = r.bottom - r.top; 04985 info.dimstride[0] = 4; 04986 info.dimstride[1] = GetPixRowBytes(pmh); 04987 info.size = info.dimstride[1] * info.dim[1]; 04988 jit_object_method(x->wrapmatrix, _jit_sym_setinfo_ex, &info); 04989 jit_object_method(x->wrapmatrix, _jit_sym_data, GetPixBaseAddr(pmh)); 04990 04991 x->cmode_changed = CMODE_UNCHANGED; 04992 } 04993 } 04994 return err; 04995 } 04996 04997 void jit_qt_movie_task_schedule(t_jit_qt_movie *x) 04998 { 04999 defer_low(x, (method)jit_qt_movie_task, NULL, 0, NULL); 05000 } 05001 05002 static void TaskNeededSoonerCallback(TimeValue duration, unsigned long flags, void *refcon) 05003 { 05004 t_jit_qt_movie *x = (t_jit_qt_movie *)refcon; 05005 05006 jit_object_post((t_object *)x,"got task needed sooner callback %ld", duration); 05007 clock_fdelay(x->taskclock, duration); 05008 } 05009 05010 long jit_qt_movie_task(t_jit_qt_movie *x) 05011 { 05012 OSErr err; 05013 PREP_M 05014 05015 #ifdef MAC_VERSION 05016 if (m && qt64) { 05017 Boolean here = false, anywhere = false; 05018 05019 mGetMovieThreadAttachState(m, &here, &anywhere); 05020 if (here) 05021 #else 05022 if (m) { 05023 #endif 05024 MoviesTask(m, 0); 05025 #ifdef TASKTEST 05026 { 05027 OSErr error; 05028 long durationInMilliseconds; 05029 double tasktime; 05030 05031 if (x->fps || (x->fps = jit_attr_getfloat(x, ps_fps))) { 05032 tasktime = 1000. / x->fps; 05033 } else 05034 tasktime = JIT_MIN_TASKTIME; 05035 // ask the idle manager when we should fire the next time 05036 error = QTGetTimeUntilNextTask(&durationInMilliseconds, 1000); 05037 if (noErr != error) { 05038 jit_object_post((t_object *)x,"could not get time until next task"); 05039 clock_fdelay(x->taskclock, tasktime); 05040 return JIT_ERR_NONE; 05041 } 05042 // When zero, pin the duration to our minimum 05043 // 0x7FFFFFFF is returned when rate = 0 05044 if (durationInMilliseconds == 0) { 05045 durationInMilliseconds = tasktime; 05046 } else if (durationInMilliseconds == 0x7FFFFFFF) { 05047 return JIT_ERR_NONE; // don't reschedule 05048 } 05049 /* 05050 else { 05051 jit_object_post((t_object *)x,"asking for %ld ms for next task", durationInMilliseconds); 05052 } 05053 */ 05054 clock_fdelay(x->taskclock, durationInMilliseconds); 05055 } 05056 #endif 05057 return JIT_ERR_NONE; 05058 } 05059 return JIT_ERR_GENERIC; 05060 } 05061 05062 Boolean jit_qt_movie_clear_mcalc(t_jit_qt_movie *x, void *matrix, long clear) 05063 { 05064 if (clear) { 05065 jit_qt_movie_clear_offscreen(x); // sets clearflag to 0 05066 if (matrix) { // need to check if it's a wrapped matrix or not - don't clear in that instance 05067 if (x->colormode == ps_uyvy) { 05068 jit_object_method(matrix, _jit_sym_clear_custom, 0x80108010); 05069 jit_object_method(x->ayuvmatrix, _jit_sym_clear_custom, 0xFF108080); 05070 jit_object_method(x->ayuvSmatrix, _jit_sym_clear_custom, 0xFF108080); 05071 } 05072 else 05073 jit_object_method(matrix, _jit_sym_clear_custom, 0xFF000000); 05074 } 05075 return true; 05076 } 05077 return false; 05078 } 05079 05080 // the gworld is ALWAYS the same size as the movie's native size. We need to test 05081 // to be certain that we don't need to scale. This is no problem in argb mode, but 05082 // in uyvy mode, we have to do a conversion to ayuv, scale and the reconvert, even 05083 // when we're not using srcrect/dstrect 05084 void jit_qt_movie_fromgworld(t_jit_qt_movie *x, void *out_matrix, t_matrix_conv_info *ci) 05085 { 05086 Rect r; 05087 long width, height = x->dim[1]; // argb matrix dims 05088 long offw, offh; 05089 t_jit_matrix_info info; 05090 PixMapHandle pmh; 05091 void *wrapmatrix = x->wrapmatrix; 05092 char rebuild = false; 05093 char optimize = (_jit_qt_optimize && x->optimize && !x->cmode_changed && !(x->mwrapped == MWRAP_TRYAGAIN)); 05094 GWorldPtr gw = NULL; 05095 OSErr err; 05096 char *bp = NULL; 05097 05098 if (x->loadingmovie) return; // hold previous picture 05099 05100 r = x->movie_rect; 05101 offw = r.right - r.left; 05102 offh = r.bottom - r.top; 05103 05104 x->mxmodify = true; 05105 jit_object_method(out_matrix, _jit_sym_getinfo, &info); 05106 if (x->adapt) { 05107 width = offw; 05108 height = offh; 05109 if (info.dim[0] != ((x->colormode == ps_uyvy) ? (width / 2) : width) || (info.dim[1] != height)) { 05110 jit_qt_movie_dim(x, width, height); 05111 optimize = false; 05112 } 05113 } 05114 else { 05115 if (x->optimize) { // we're in a box 05116 width = x->dim[0]; 05117 height = x->dim[1]; 05118 } 05119 else { // assume that the user has it under control. use the matrix dims and don't change anything. 05120 width = (x->colormode == ps_uyvy) ? info.dim[0] * 2 : info.dim[0]; 05121 height = info.dim[1]; 05122 } 05123 } 05124 05125 if (x->colormode == ps_uyvy) { 05126 long wd2 = width / 2; // desired output matrix width 05127 05128 if (optimize && !ci && width == offw && height == offh) { // wrap matrix - if cmode has changed, the first time through is unwrapped and the matrix is resized 05129 if (x->mwrapped != MWRAP_WRAPPED) { 05130 jit_object_method(out_matrix, _jit_sym_getdata, &bp); 05131 if (!bp) { 05132 jit_object_error((t_object *)x, "jit.qt.movie: could not get matrix data pointer"); 05133 } 05134 else { 05135 if (err = QTNewGWorldFromPtr(&gw, x->pixelformat, &x->movie_rect, NULL, NULL, 0, bp, info.dimstride[1])) { 05136 jit_object_error((t_object *)x, "jit.qt.movie: could not optimize gworld (%d)", err); 05137 x->mwrapped = MWRAP_UNWRAPPED; 05138 } 05139 else { 05140 // jit_object_post((t_object *)x,"wrapped matrix"); 05141 jit_qt_movie_dispose_gworld(x); 05142 x->offscreen = gw; 05143 SetMovieGWorld(x->movie, x->offscreen, NULL); 05144 x->mwrapped = MWRAP_WRAPPED; 05145 if (x->moviecontroller) 05146 MCMovieChanged(x->moviecontroller, x->movie); 05147 } 05148 } 05149 } 05150 pmh = GetGWorldPixMap(x->offscreen); 05151 #ifndef TASKTEST 05152 LockPixels(pmh); 05153 jit_qt_movie_task(x); 05154 UnlockPixels(pmh); 05155 #endif 05156 } 05157 else { // copy, unwrap matrix if necessary 05158 if (x->cmode_changed || x->mwrapped == MWRAP_WRAPPED) { // no optimize check in case optimize state changed during run 05159 jit_qt_movie_mreset(x); 05160 } 05161 x->mwrapped = MWRAP_UNWRAPPED; // in case of MWRAP_TRYAGAIN 05162 05163 if ((info.dim[0] != wd2) || (info.dim[1] != height)) { 05164 info.dim[0] = wd2; 05165 info.dim[1] = height; 05166 jit_object_method(out_matrix, _jit_sym_setinfo, &info); 05167 } 05168 05169 pmh = GetGWorldPixMap(x->offscreen); 05170 LockPixels(pmh); 05171 #ifndef TASKTEST 05172 jit_qt_movie_task(x); 05173 #endif 05174 if (info.dim[0] == (offw/2) && info.dim[1] == offh && !ci) { // no scaling necessary 05175 jit_object_method(out_matrix, _jit_sym_frommatrix, wrapmatrix, NULL); 05176 } 05177 else { // we have to scale image. this is slow. use wrapmatrix to avoid extra copy step. 05178 void *ayuvmatrix = x->ayuvmatrix; 05179 void *ayuvSmatrix = x->ayuvSmatrix; 05180 05181 // convert to (non-scaled) ayuv (2x width) 05182 jit_object_method(x->uyvy2ayuv, _jit_sym_matrix_calc, wrapmatrix, ayuvmatrix); 05183 // scale ayuv, should be same size as out_matrix with 2x width 05184 jit_object_method(ayuvSmatrix, _jit_sym_getinfo, &info); 05185 if ((info.dim[0] != width) || (info.dim[1] != height)) { 05186 info.dim[0] = width; 05187 info.dim[1] = height; 05188 jit_object_method(ayuvSmatrix, _jit_sym_setinfo, &info); 05189 } 05190 jit_object_method(ayuvSmatrix, _jit_sym_frommatrix, ayuvmatrix, ci); 05191 // convert back to uyvy 05192 jit_object_method(x->ayuv2uyvy, _jit_sym_matrix_calc, ayuvSmatrix, out_matrix); 05193 } 05194 UnlockPixels(pmh); 05195 } 05196 } 05197 else { 05198 if (optimize && !ci && width == offw && height == offh) { // wrap matrix - if cmode has changed, the first time through is unwrapped and the matrix is resized 05199 if (x->mwrapped != MWRAP_WRAPPED) { 05200 jit_object_method(out_matrix, _jit_sym_getdata, &bp); 05201 if (!bp) { 05202 jit_object_error((t_object *)x, "jit.qt.movie: could not get matrix data pointer"); 05203 } 05204 else { 05205 if (err = QTNewGWorldFromPtr(&gw, x->pixelformat, &x->movie_rect, NULL, NULL, 0, bp, info.dimstride[1])) { 05206 jit_object_error((t_object *)x, "jit.qt.movie: could not optimize gworld (%d)", err); 05207 x->mwrapped = MWRAP_UNWRAPPED; 05208 } 05209 else { 05210 // jit_object_post((t_object *)x,"wrapped matrix"); 05211 jit_qt_movie_dispose_gworld(x); 05212 x->offscreen = gw; 05213 SetMovieGWorld(x->movie, x->offscreen, NULL); 05214 x->mwrapped = MWRAP_WRAPPED; 05215 if (x->moviecontroller) 05216 MCMovieChanged(x->moviecontroller, x->movie); 05217 } 05218 } 05219 } 05220 pmh = GetGWorldPixMap(x->offscreen); 05221 #ifndef TASKTEST 05222 LockPixels(pmh); 05223 jit_qt_movie_task(x); 05224 UnlockPixels(pmh); 05225 #endif 05226 } 05227 else { // copy, unwrap matrix if necessary 05228 if (x->cmode_changed || x->mwrapped == MWRAP_WRAPPED) { // no optimize check in case optimize state changed during run 05229 jit_qt_movie_mreset(x); 05230 } 05231 x->mwrapped = MWRAP_UNWRAPPED; // in case of MWRAP_TRYAGAIN 05232 if ((info.dim[0] != width) || (info.dim[1] != height)) { 05233 info.dim[0] = width; 05234 info.dim[1] = height; 05235 jit_object_method(out_matrix, _jit_sym_setinfo, &info); 05236 } 05237 05238 pmh = GetGWorldPixMap(x->offscreen); 05239 if (pmh) { 05240 LockPixels(pmh); 05241 #ifndef TASKTEST 05242 jit_qt_movie_task(x); 05243 #endif 05244 jit_object_method(out_matrix, _jit_sym_frommatrix, wrapmatrix, ci); 05245 UnlockPixels(pmh); 05246 } 05247 } 05248 } 05249 x->mxmodify = false; 05250 } 05251 05252 void jit_qt_movie_matrixattach(t_jit_qt_movie *x, void *matrix) 05253 { 05254 void *mxptr; 05255 t_symbol *mxname; 05256 05257 if (!(mxptr = jit_object_method(matrix, _jit_sym_getmatrix))) 05258 mxptr = matrix; 05259 mxname = jit_object_findregisteredbyptr(mxptr); 05260 05261 if (x->mxname != mxname) { 05262 jit_object_detach(x->mxname, x); 05263 x->mxname = mxname; 05264 jit_object_attach(x->mxname, x); 05265 } 05266 } 05267 05268 /** 05269 * matrix_calc method for the jit.qt.movie object 05270 * 05271 * @ingroup qtmoviemod 05272 * 05273 * @param x t_jit_qt_movie object pointer 05274 * @param inputs input list (unused) 05275 * @param outputs output list (should be or contain 1 t_jit_matrix object) 05276 * 05277 * @return t_jit_err error code 05278 * 05279 * @warning This function is not exported, but is provided 05280 * for reference when calling via jit_object_method 05281 * on an instance of a t_jit_qt_movie object. 05282 */ 05283 long jit_qt_movie_matrix_calc(t_jit_qt_movie *x, void *inputs, void *outputs) 05284 { 05285 t_jit_err err = JIT_ERR_NONE; 05286 t_matrix_conv_info ci; 05287 void *out_matrix; 05288 long savelock, i; 05289 void *jw; 05290 UnsignedWide ms1, ms2; 05291 t_jit_matrix_info info; 05292 Boolean here = true, anywhere; 05293 long clear=x->clearflag; //needed in both mreset and clear_mcalc 05294 05295 if (!(out_matrix = jit_object_method(outputs, _jit_sym_getindex, 0))) 05296 return JIT_ERR_INVALID_PTR; 05297 05298 if (!x->movie) { 05299 if (x->cmode_changed) { 05300 jit_qt_movie_fromgworld(x, out_matrix, NULL); // CMODE_UNCHANGED will be set in mreset() 05301 } 05302 jit_qt_movie_clear_mcalc(x, out_matrix, clear); 05303 return JIT_ERR_NONE; 05304 } 05305 05306 if (jit_qt_movie_threadstate_get(x, THREADSTATE_UNSAFE)) 05307 return JIT_ERR_NONE; 05308 05309 if (x->framereport) 05310 Microseconds(&ms1); 05311 05312 if (SPIGOTTED) { 05313 if (x->sfplay_clock_enabled) { 05314 // get current position 05315 double pos, poserr, realpos; 05316 TimeScale timescale; 05317 05318 jit_qt_movie_soc_timingvectors_get(x, &pos, &poserr); 05319 realpos = (pos + poserr) / 1000.; 05320 05321 timescale = GetMovieTimeScale(x->movie); 05322 SetMovieTimeValue(x->movie, (TimeValue)(realpos * timescale)); 05323 } 05324 } 05325 05326 if ((x->window != _jit_sym_nothing) && 05327 (jw = jit_object_findregistered(x->window)) && 05328 (jit_object_method(jw, ps_class_jit_window))) 05329 { 05330 #ifndef TASKTEST 05331 jit_qt_movie_task(x); 05332 #endif 05333 err = JIT_ERR_SUPPRESS_OUTPUT; 05334 goto bail; 05335 } 05336 else if (!x->mode) { // we're not in a voc mode 05337 if (!jit_qt_movie_unique_getready(x)) 05338 return JIT_ERR_SUPPRESS_OUTPUT; 05339 05340 if (x && x->offscreen) { 05341 jit_object_method(out_matrix, _jit_sym_getinfo, &info); 05342 ci.flags = 0; 05343 if (x->usesrcrect) 05344 ci.flags |= JIT_MATRIX_CONVERT_SRCDIM; 05345 if (x->usedstrect) 05346 ci.flags |= JIT_MATRIX_CONVERT_DSTDIM; 05347 if (ci.flags || info.planecount != 4) { 05348 if (x->interp) 05349 ci.flags |= JIT_MATRIX_CONVERT_INTERP; 05350 // this weirdness mimics the behavior of jit_matrix_fromgworld, for legacy reasons 05351 for (i = 0; i < MAX(4, info.planecount); i++) 05352 ci.planemap[i % info.planecount] = i; 05353 ci.srcdimstart[0] = x->srcrect[0]; 05354 ci.srcdimstart[1] = x->srcrect[1]; 05355 ci.srcdimend[0] = x->srcrect[2]; 05356 ci.srcdimend[1] = x->srcrect[3]; 05357 ci.dstdimstart[0] = x->dstrect[0]; 05358 ci.dstdimstart[1] = x->dstrect[1]; 05359 ci.dstdimend[0] = x->dstrect[2]; 05360 ci.dstdimend[1] = x->dstrect[3]; 05361 } 05362 05363 savelock = (long)jit_object_method(out_matrix, _jit_sym_lock, 1); 05364 jit_qt_movie_matrixattach(x, out_matrix); 05365 jit_qt_movie_fromgworld(x, out_matrix, (ci.flags || info.planecount != 4) ? &ci : NULL); 05366 jit_qt_movie_clear_mcalc(x, out_matrix, clear); 05367 x->cmode_changed = CMODE_UNCHANGED; 05368 05369 if (x->restoreloop && GetMovieRate(x->movie)) { 05370 jit_qt_movie_restoreloop(x); 05371 } 05372 05373 jit_object_method(out_matrix, _jit_sym_lock, savelock); 05374 err = JIT_ERR_NONE; 05375 goto bail; 05376 } 05377 else { 05378 return JIT_ERR_INVALID_PTR; 05379 } 05380 } 05381 else { 05382 if (x->open) { 05383 long is_owner; 05384 05385 if (!x->ci || !x->offscreen) { 05386 err = JIT_ERR_NONE; 05387 goto bail; 05388 } 05389 05390 is_owner = (long)jit_object_method(x->qtc, gensym("is_owner"), x); 05391 05392 if (!x->prepped || !is_owner) 05393 jit_qt_movie_prep_output(x); 05394 05395 if (x->restoreloop && GetMovieRate(x->movie)) 05396 jit_qt_movie_restoreloop(x); 05397 05398 #ifndef TASKTEST 05399 jit_qt_movie_task(x); 05400 #endif 05401 err = JIT_ERR_SUPPRESS_OUTPUT; 05402 } 05403 } 05404 bail: 05405 if (x->framereport) { 05406 double d=0; 05407 t_atom a; 05408 05409 Microseconds(&ms2); 05410 if (ms2.lo < ms1.lo) { 05411 d = (double)0xFFFFFFFF; 05412 d = ((double)ms2.lo + d - (double)ms1.lo); 05413 } else 05414 d = ((double)ms2.lo - (double)ms1.lo); 05415 05416 jit_atom_setfloat(&a, (float)d); 05417 jit_qt_movie_notify_atomarray_prep(x, ps_framereport, 1, &a); 05418 } 05419 return err; 05420 } 05421 05422 pascal OSErr jit_qt_movie_actions(void *refcon, Track track, long trefcon, QTEventRecordPtr event) 05423 { 05424 post("actions"); 05425 return noErr; 05426 } 05427 05428 pascal Boolean MyMCActionFilterProc(MovieController mc, short action, void *params, long refcon) 05429 { 05430 t_jit_qt_movie *x = (t_jit_qt_movie *)refcon; 05431 Rect r; 05432 05433 switch (action) { 05434 // handle window resizing 05435 case mcActionControllerSizeChanged: 05436 GetMovieBox(x->movie, &r); 05437 if (r.left == 0 && r.right == 0 && r.top == 0 && r.bottom == 0) { // no box 05438 r.right = 320; 05439 r.bottom = 240; 05440 } 05441 if (x->window == _jit_sym_nothing) { // DO NOT change x->movie_rect when drawing to a window or everything gets messed up! 05442 x->movie_rect = r; 05443 jit_qt_movie_mreset(x); 05444 } 05445 jit_qt_movie_movie_prep(x); // in case we're drawing to a window 05446 break; 05447 default: 05448 break; 05449 } 05450 return(false); 05451 } 05452 05453 void jit_qt_movie_mc(t_jit_qt_movie *x) 05454 { 05455 Rect r; 05456 CGrafPtr port; 05457 GDHandle gdh; 05458 PREP_M 05459 05460 if (m && x->offscreen && (!x->moviecontroller)) { 05461 r = x->movie_rect; 05462 GetGWorld(&port, &gdh); 05463 SetGWorld(x->offscreen, NULL); 05464 x->moviecontroller = NewMovieController(m,&r,mcNotVisible|mcTopLeftMovie); 05465 MCSetActionFilterWithRefCon(x->moviecontroller, NewMCActionFilterWithRefConUPP(MyMCActionFilterProc), (long)x); 05466 // MCSetActionFilterWithRefCon(x->moviecontroller, x->mcactionfilter, (long)x); 05467 SetGWorld(port, gdh); 05468 #ifdef JUNK 05469 if (0) { 05470 Track track; 05471 Media media; 05472 05473 if (track = GetMovieIndTrackType(m, 1, FlashMediaType, movieTrackMediaType)) { 05474 if (media = GetTrackMedia(track)) { 05475 MediaSetActionsCallback(GetMediaHandler(media), NewActionsUPP(jit_qt_movie_actions), (void *)x); 05476 jit_object_post((t_object *)x,"set actions callback"); 05477 } 05478 } 05479 } 05480 #endif 05481 } 05482 }
Copyright © 2008, Cycling '74